inspector: Add Inspector. (#897)
<img width="1434" alt="image" src="https://github.com/user-attachments/assets/f6ec2e1d-ff1c-4798-90fe-d29bef20fa9d" />
This commit is contained in:
parent
a1ad647527
commit
1c11b5fb55
13 changed files with 310 additions and 42 deletions
18
assets/icons/inspector.svg
Normal file
18
assets/icons/inspector.svg
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-square-dashed-mouse-pointer-icon lucide-square-dashed-mouse-pointer"
|
||||
><path
|
||||
d="M12.034 12.681a.498.498 0 0 1 .647-.647l9 3.5a.5.5 0 0 1-.033.943l-3.444 1.068a1 1 0 0 0-.66.66l-1.067 3.443a.5.5 0 0 1-.943.033z"
|
||||
/><path d="M5 3a2 2 0 0 0-2 2" /><path d="M19 3a2 2 0 0 1 2 2" /><path
|
||||
d="M5 21a2 2 0 0 1-2-2"
|
||||
/><path d="M9 3h1" /><path d="M9 21h2" /><path d="M14 3h1" /><path
|
||||
d="M3 9v1"
|
||||
/><path d="M21 9v2" /><path d="M3 14v1" /></svg>
|
||||
|
After Width: | Height: | Size: 710 B |
|
|
@ -1,5 +1,3 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use gpui::*;
|
||||
use gpui_component::{
|
||||
checkbox::Checkbox,
|
||||
|
|
@ -11,9 +9,6 @@ use gpui_component::{
|
|||
};
|
||||
use story::Assets;
|
||||
|
||||
static LIGHT_THEME: LazyLock<HighlightTheme> = LazyLock::new(|| HighlightTheme::default_light());
|
||||
static DARK_THEME: LazyLock<HighlightTheme> = LazyLock::new(|| HighlightTheme::default_dark());
|
||||
|
||||
pub struct Example {
|
||||
input_state: Entity<InputState>,
|
||||
language_state: Entity<DropdownState<Vec<SharedString>>>,
|
||||
|
|
@ -31,7 +26,7 @@ impl Example {
|
|||
let default_language: SharedString = LANGUAGES[0].into();
|
||||
let input_state = cx.new(|cx| {
|
||||
InputState::new(window, cx)
|
||||
.code_editor(Some(&default_language), &LIGHT_THEME)
|
||||
.code_editor(Some(&default_language), &HighlightTheme::default_light())
|
||||
.line_number(true)
|
||||
.tab_size(TabSize {
|
||||
tab_size: 4,
|
||||
|
|
@ -89,9 +84,15 @@ impl Example {
|
|||
self.is_dark = is_dark;
|
||||
self.input_state.update(cx, |state, cx| {
|
||||
if is_dark {
|
||||
state.set_highlighter(Highlighter::new(Some(language), &DARK_THEME), cx);
|
||||
state.set_highlighter(
|
||||
Highlighter::new(Some(language), &HighlightTheme::default_dark()),
|
||||
cx,
|
||||
);
|
||||
} else {
|
||||
state.set_highlighter(Highlighter::new(Some(language), &LIGHT_THEME), cx);
|
||||
state.set_highlighter(
|
||||
Highlighter::new(Some(language), &HighlightTheme::default_dark()),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use gpui::*;
|
||||
use gpui_component::{
|
||||
highlighter::{HighlightTheme, Highlighter},
|
||||
|
|
@ -10,9 +8,6 @@ use gpui_component::{
|
|||
};
|
||||
use story::Assets;
|
||||
|
||||
static LIGHT_THEME: LazyLock<HighlightTheme> = LazyLock::new(|| HighlightTheme::default_light());
|
||||
static DARK_THEME: LazyLock<HighlightTheme> = LazyLock::new(|| HighlightTheme::default_dark());
|
||||
|
||||
pub struct Example {
|
||||
input_state: Entity<InputState>,
|
||||
resizable_state: Entity<ResizableState>,
|
||||
|
|
@ -27,7 +22,7 @@ impl Example {
|
|||
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let input_state = cx.new(|cx| {
|
||||
InputState::new(window, cx)
|
||||
.code_editor(Some(LANG), &LIGHT_THEME)
|
||||
.code_editor(Some(LANG), &HighlightTheme::default_light())
|
||||
.tab_size(TabSize {
|
||||
tab_size: 4,
|
||||
hard_tabs: false,
|
||||
|
|
@ -65,9 +60,15 @@ impl Render for Example {
|
|||
self.is_dark = is_dark;
|
||||
self.input_state.update(cx, |state, cx| {
|
||||
if is_dark {
|
||||
state.set_highlighter(Highlighter::new(Some(LANG), &DARK_THEME), cx);
|
||||
state.set_highlighter(
|
||||
Highlighter::new(Some(LANG), &HighlightTheme::default_dark()),
|
||||
cx,
|
||||
);
|
||||
} else {
|
||||
state.set_highlighter(Highlighter::new(Some(LANG), &LIGHT_THEME), cx);
|
||||
state.set_highlighter(
|
||||
Highlighter::new(Some(LANG), &HighlightTheme::default_light()),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{rc::Rc, sync::LazyLock};
|
||||
use std::rc::Rc;
|
||||
|
||||
use gpui::*;
|
||||
use gpui_component::{
|
||||
|
|
@ -10,8 +10,6 @@ use gpui_component::{
|
|||
};
|
||||
use story::Assets;
|
||||
|
||||
static LIGHT_THEME: LazyLock<HighlightTheme> = LazyLock::new(|| HighlightTheme::default_light());
|
||||
static DARK_THEME: LazyLock<HighlightTheme> = LazyLock::new(|| HighlightTheme::default_dark());
|
||||
const LANG: &str = "markdown";
|
||||
|
||||
pub struct Example {
|
||||
|
|
@ -26,7 +24,7 @@ impl Example {
|
|||
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let input_state = cx.new(|cx| {
|
||||
InputState::new(window, cx)
|
||||
.code_editor(Some(LANG), &LIGHT_THEME)
|
||||
.code_editor(Some(LANG), &HighlightTheme::default_light())
|
||||
.line_number(false)
|
||||
.tab_size(TabSize {
|
||||
tab_size: 2,
|
||||
|
|
@ -66,9 +64,15 @@ impl Render for Example {
|
|||
self.is_dark = is_dark;
|
||||
self.input_state.update(cx, |state, cx| {
|
||||
if is_dark {
|
||||
state.set_highlighter(Highlighter::new(Some(LANG), &DARK_THEME), cx);
|
||||
state.set_highlighter(
|
||||
Highlighter::new(Some(LANG), &HighlightTheme::default_dark()),
|
||||
cx,
|
||||
);
|
||||
} else {
|
||||
state.set_highlighter(Highlighter::new(Some(LANG), &LIGHT_THEME), cx);
|
||||
state.set_highlighter(
|
||||
Highlighter::new(Some(LANG), &HighlightTheme::default_light()),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -92,7 +96,7 @@ impl Render for Example {
|
|||
.child(
|
||||
TextView::markdown("preview", self.input_state.read(cx).value()).style(
|
||||
TextViewStyle {
|
||||
highlight_theme: Rc::new(theme),
|
||||
highlight_theme: Rc::new(theme.clone()),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use gpui_component::{
|
|||
popup_menu::PopupMenuExt as _,
|
||||
scroll::ScrollbarShow,
|
||||
set_locale, ActiveTheme as _, ContextModal as _, IconName, Sizable as _, Theme, ThemeMode,
|
||||
TitleBar,
|
||||
TitleBar, ToggleInspector,
|
||||
};
|
||||
|
||||
use crate::{SelectFont, SelectLocale, SelectRadius, SelectScrollbarShow};
|
||||
|
|
@ -312,6 +312,8 @@ impl Render for FontSizeSelector {
|
|||
scroll_show == ScrollbarShow::Always,
|
||||
Box::new(SelectScrollbarShow(ScrollbarShow::Always)),
|
||||
)
|
||||
.separator()
|
||||
.menu("Inspector", Box::new(ToggleInspector))
|
||||
})
|
||||
.anchor(Corner::TopRight),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,12 @@ impl From<SharedString> for DescriptionText {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<String> for DescriptionText {
|
||||
fn from(text: String) -> Self {
|
||||
DescriptionText::String(SharedString::from(text))
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for DescriptionText {
|
||||
fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
|
||||
match self {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,15 @@ static DEFAULT_DARK: LazyLock<Arc<highlighting::Theme>> = LazyLock::new(|| {
|
|||
Arc::new(highlighting::ThemeSet::load_from_reader(&mut cursor).unwrap())
|
||||
});
|
||||
|
||||
pub static LIGHT_THEME: LazyLock<HighlightTheme> = LazyLock::new(|| HighlightTheme {
|
||||
name: "default-light".into(),
|
||||
inner: DEFAULT_LIGHT.clone(),
|
||||
});
|
||||
pub static DARK_THEME: LazyLock<HighlightTheme> = LazyLock::new(|| HighlightTheme {
|
||||
name: "default-dark".into(),
|
||||
inner: DEFAULT_DARK.clone(),
|
||||
});
|
||||
|
||||
/// Represents a theme for syntax highlighting.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct HighlightTheme {
|
||||
|
|
@ -27,19 +36,13 @@ pub struct HighlightTheme {
|
|||
|
||||
impl HighlightTheme {
|
||||
/// Default light theme.
|
||||
pub fn default_light() -> Self {
|
||||
Self {
|
||||
name: "default-light".into(),
|
||||
inner: DEFAULT_LIGHT.clone(),
|
||||
}
|
||||
pub fn default_light() -> &'static Self {
|
||||
&LIGHT_THEME
|
||||
}
|
||||
|
||||
/// Default dark theme.
|
||||
pub fn default_dark() -> Self {
|
||||
Self {
|
||||
name: "default-dark".into(),
|
||||
inner: DEFAULT_DARK.clone(),
|
||||
}
|
||||
pub fn default_dark() -> &'static Self {
|
||||
&DARK_THEME
|
||||
}
|
||||
|
||||
/// Parse a theme from a string (tmTheme)
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ pub enum IconName {
|
|||
HeartOff,
|
||||
Inbox,
|
||||
Info,
|
||||
Inspector,
|
||||
LayoutDashboard,
|
||||
Loader,
|
||||
LoaderCircle,
|
||||
|
|
@ -122,6 +123,7 @@ impl IconName {
|
|||
Self::HeartOff => "icons/heart-off.svg",
|
||||
Self::Inbox => "icons/inbox.svg",
|
||||
Self::Info => "icons/info.svg",
|
||||
Self::Inspector => "icons/inspector.svg",
|
||||
Self::LayoutDashboard => "icons/layout-dashboard.svg",
|
||||
Self::Loader => "icons/loader.svg",
|
||||
Self::LoaderCircle => "icons/loader-circle.svg",
|
||||
|
|
|
|||
|
|
@ -614,7 +614,13 @@ impl InputState {
|
|||
self.replace_text(value, window, cx);
|
||||
self.history.ignore = false;
|
||||
// Ensure cursor to start when set text
|
||||
self.selected_range = self.text.len()..self.text.len();
|
||||
if self.is_single_line() {
|
||||
self.selected_range = self.text.len()..self.text.len();
|
||||
} else {
|
||||
self.selected_range = 0..0;
|
||||
}
|
||||
// Move scroll to top
|
||||
self.scroll_handle.set_offset(point(px(0.), px(0.)));
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,6 +180,12 @@ impl RenderOnce for TextInput {
|
|||
.on_action(window.listener_for(&self.state, InputState::delete_next_word))
|
||||
.on_action(window.listener_for(&self.state, InputState::enter))
|
||||
.on_action(window.listener_for(&self.state, InputState::escape))
|
||||
.on_action(window.listener_for(&self.state, InputState::indent))
|
||||
.on_action(window.listener_for(&self.state, InputState::outdent))
|
||||
.on_action(window.listener_for(&self.state, InputState::paste))
|
||||
.on_action(window.listener_for(&self.state, InputState::cut))
|
||||
.on_action(window.listener_for(&self.state, InputState::undo))
|
||||
.on_action(window.listener_for(&self.state, InputState::redo))
|
||||
})
|
||||
.on_action(window.listener_for(&self.state, InputState::left))
|
||||
.on_action(window.listener_for(&self.state, InputState::right))
|
||||
|
|
@ -190,8 +196,6 @@ impl RenderOnce for TextInput {
|
|||
.on_action(window.listener_for(&self.state, InputState::down))
|
||||
.on_action(window.listener_for(&self.state, InputState::select_up))
|
||||
.on_action(window.listener_for(&self.state, InputState::select_down))
|
||||
.on_action(window.listener_for(&self.state, InputState::indent))
|
||||
.on_action(window.listener_for(&self.state, InputState::outdent))
|
||||
})
|
||||
.on_action(window.listener_for(&self.state, InputState::select_all))
|
||||
.on_action(window.listener_for(&self.state, InputState::select_to_start_of_line))
|
||||
|
|
@ -208,10 +212,6 @@ impl RenderOnce for TextInput {
|
|||
.on_action(window.listener_for(&self.state, InputState::select_to_end))
|
||||
.on_action(window.listener_for(&self.state, InputState::show_character_palette))
|
||||
.on_action(window.listener_for(&self.state, InputState::copy))
|
||||
.on_action(window.listener_for(&self.state, InputState::paste))
|
||||
.on_action(window.listener_for(&self.state, InputState::cut))
|
||||
.on_action(window.listener_for(&self.state, InputState::undo))
|
||||
.on_action(window.listener_for(&self.state, InputState::redo))
|
||||
.on_key_down(window.listener_for(&self.state, InputState::on_key_down))
|
||||
.on_mouse_down(
|
||||
MouseButton::Left,
|
||||
|
|
|
|||
222
crates/ui/src/inspector.rs
Normal file
222
crates/ui/src/inspector.rs
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
use std::cell::OnceCell;
|
||||
|
||||
use gpui::{
|
||||
actions, div, prelude::FluentBuilder, px, AnyElement, App, AppContext as _, Context,
|
||||
DivInspectorState, Entity, Inspector, InspectorElementId, InteractiveElement as _, IntoElement,
|
||||
KeyBinding, ParentElement as _, Render, SharedString, Styled, Window,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
button::{Button, ButtonVariants},
|
||||
clipboard::Clipboard,
|
||||
description_list::DescriptionList,
|
||||
h_flex,
|
||||
highlighter::HighlightTheme,
|
||||
input::{InputState, TextInput},
|
||||
link::Link,
|
||||
v_flex, ActiveTheme, IconName, Selectable, Sizable, TITLE_BAR_HEIGHT,
|
||||
};
|
||||
|
||||
actions!(inspector, [ToggleInspector]);
|
||||
|
||||
/// Initialize the inspector and register the action to toggle it.
|
||||
pub fn init(cx: &mut App) {
|
||||
cx.bind_keys(vec![
|
||||
#[cfg(target_os = "macos")]
|
||||
KeyBinding::new("cmd-alt-i", ToggleInspector, None),
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
KeyBinding::new("ctrl-shift-i", ToggleInspector, None),
|
||||
]);
|
||||
|
||||
cx.on_action(|_: &ToggleInspector, cx| {
|
||||
let Some(active_window) = cx.active_window() else {
|
||||
return;
|
||||
};
|
||||
|
||||
cx.defer(move |cx| {
|
||||
_ = active_window.update(cx, |_, window, cx| {
|
||||
window.toggle_inspector(cx);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
let inspector_el = OnceCell::new();
|
||||
cx.register_inspector_element(move |id, state: &DivInspectorState, window, cx| {
|
||||
let el = inspector_el.get_or_init(|| cx.new(|cx| DivInspector::new(window, cx)));
|
||||
el.update(cx, |this, cx| {
|
||||
this.set_inspector_state(id, state.clone(), cx);
|
||||
this.render(window, cx).into_any_element()
|
||||
})
|
||||
});
|
||||
|
||||
cx.set_inspector_renderer(Box::new(render_inspector));
|
||||
}
|
||||
|
||||
pub struct DivInspector {
|
||||
inspector_id: Option<InspectorElementId>,
|
||||
inspector_state: Option<DivInspectorState>,
|
||||
input_state: Entity<InputState>,
|
||||
}
|
||||
|
||||
impl DivInspector {
|
||||
pub fn new(window: &mut Window, cx: &mut App) -> Self {
|
||||
let theme = if cx.theme().is_dark() {
|
||||
HighlightTheme::default_dark()
|
||||
} else {
|
||||
HighlightTheme::default_light()
|
||||
};
|
||||
|
||||
let input_state = cx.new(|cx| {
|
||||
let mut state = InputState::new(window, cx)
|
||||
.code_editor(Some("json"), theme)
|
||||
.line_number(false);
|
||||
state.set_disabled(true, window, cx);
|
||||
state
|
||||
});
|
||||
|
||||
Self {
|
||||
inspector_id: None,
|
||||
inspector_state: None,
|
||||
input_state,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_inspector_state(
|
||||
&mut self,
|
||||
inspector_id: InspectorElementId,
|
||||
state: DivInspectorState,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.inspector_id = Some(inspector_id);
|
||||
self.inspector_state = Some(state);
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for DivInspector {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let input_state = self.input_state.clone();
|
||||
let last_styles = input_state.read(cx).value().clone();
|
||||
|
||||
v_flex().size_full().gap_3().text_sm().when_some(
|
||||
self.inspector_state.clone(),
|
||||
|this, state| {
|
||||
let styles = serde_json::to_string_pretty(&state.base_style);
|
||||
let styles: SharedString = match styles {
|
||||
Ok(json) => json,
|
||||
Err(e) => format!("{{ \"error\": \"{}\" }}", e),
|
||||
}
|
||||
.into();
|
||||
|
||||
if styles != last_styles {
|
||||
input_state.update(cx, |s, cx| s.set_value(styles.clone(), window, cx));
|
||||
}
|
||||
|
||||
this.child(
|
||||
DescriptionList::new()
|
||||
.columns(1)
|
||||
.label_width(px(110.))
|
||||
.bordered(false)
|
||||
.child("Origin", format!("{}", state.bounds.origin), 1)
|
||||
.child("Size", format!("{}", state.bounds.size), 1)
|
||||
.child("Content Size", format!("{}", state.content_size), 1),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.w_full()
|
||||
.flex_1()
|
||||
.gap_1()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().description_list_label_foreground)
|
||||
.child("Styles")
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
.w_full()
|
||||
.font_family("Monaco")
|
||||
.text_size(px(12.))
|
||||
.child(TextInput::new(&input_state).h_full()),
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn render_inspector(
|
||||
inspector: &mut Inspector,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Inspector>,
|
||||
) -> AnyElement {
|
||||
let inspector_element_id = inspector.active_element_id();
|
||||
let source_location =
|
||||
inspector_element_id.map(|id| SharedString::new(format!("{}", id.path.source_location)));
|
||||
|
||||
v_flex()
|
||||
.id("inspector")
|
||||
.size_full()
|
||||
.bg(cx.theme().background)
|
||||
.border_l_1()
|
||||
.border_color(cx.theme().border)
|
||||
.text_color(cx.theme().foreground)
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.justify_between()
|
||||
.gap_2()
|
||||
.h(TITLE_BAR_HEIGHT)
|
||||
.line_height(TITLE_BAR_HEIGHT)
|
||||
.overflow_hidden()
|
||||
.px_2()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().title_bar_border)
|
||||
.bg(cx.theme().title_bar)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.text_sm()
|
||||
.child(
|
||||
Button::new("inspect")
|
||||
.icon(IconName::Inspector)
|
||||
.selected(inspector.is_picking())
|
||||
.small()
|
||||
.ghost()
|
||||
.on_click(cx.listener(|this, _, window, _| {
|
||||
this.start_picking();
|
||||
window.refresh();
|
||||
})),
|
||||
)
|
||||
.child("Inspector"),
|
||||
)
|
||||
.child(
|
||||
Button::new("close")
|
||||
.icon(IconName::Close)
|
||||
.small()
|
||||
.ghost()
|
||||
.on_click(|_, window, cx| {
|
||||
window.dispatch_action(Box::new(ToggleInspector), cx);
|
||||
}),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.flex_1()
|
||||
.p_3()
|
||||
.gap_3()
|
||||
.when_some(source_location, |this, source_location| {
|
||||
this.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.text_sm()
|
||||
.child(
|
||||
Link::new("source-location")
|
||||
.href(format!("file://{}", source_location))
|
||||
.child(source_location.clone()),
|
||||
)
|
||||
.child(Clipboard::new("copy-source-location").value(source_location)),
|
||||
)
|
||||
})
|
||||
.children(inspector.render_inspector_states(window, cx)),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ mod colors;
|
|||
mod event;
|
||||
mod focusable;
|
||||
mod icon;
|
||||
mod inspector;
|
||||
mod kbd;
|
||||
mod menu;
|
||||
mod root;
|
||||
|
|
@ -64,6 +65,7 @@ pub use wry;
|
|||
pub use crate::Disableable;
|
||||
pub use event::InteractiveElementExt;
|
||||
pub use focusable::FocusableCycle;
|
||||
pub use inspector::*;
|
||||
pub use menu::{context_menu, popup_menu};
|
||||
pub use root::{ContextModal, Root};
|
||||
pub use styled::*;
|
||||
|
|
@ -88,6 +90,7 @@ rust_i18n::i18n!("locales", fallback = "en");
|
|||
/// You can initialize the UI module at your application's entry point.
|
||||
pub fn init(cx: &mut App) {
|
||||
theme::init(cx);
|
||||
inspector::init(cx);
|
||||
date_picker::init(cx);
|
||||
dock::init(cx);
|
||||
drawer::init(cx);
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ impl Default for TextViewStyle {
|
|||
Self {
|
||||
paragraph_gap: rems(1.),
|
||||
heading_base_font_size: px(14.),
|
||||
highlight_theme: Rc::new(HighlightTheme::default_light()),
|
||||
highlight_theme: Rc::new(HighlightTheme::default_light().clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue