assistant2: Adjust edit files design (#27762)
This PR includes design tweaks to elements involved on the "edit files" flow: the bar that appears above the message editor, buttons on the multibuffer hunks, adding keybindings to the "Review Changes" button, etc. <img src="https://github.com/user-attachments/assets/4bff883a-c5c4-443e-8bf5-d98f535c83ce" width="750" /> Release Notes: - N/A
This commit is contained in:
parent
74dd32d52c
commit
4ee20dda23
9 changed files with 165 additions and 88 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -497,6 +497,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"settings",
|
"settings",
|
||||||
|
"smallvec",
|
||||||
"smol",
|
"smol",
|
||||||
"streaming_diff",
|
"streaming_diff",
|
||||||
"telemetry",
|
"telemetry",
|
||||||
|
|
|
@ -651,7 +651,8 @@
|
||||||
"context": "MessageEditor > Editor",
|
"context": "MessageEditor > Editor",
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"enter": "assistant2::Chat",
|
"enter": "assistant2::Chat",
|
||||||
"ctrl-i": "assistant2::ToggleProfileSelector"
|
"ctrl-i": "assistant2::ToggleProfileSelector",
|
||||||
|
"shift-ctrl-r": "assistant2::OpenAssistantDiff"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -305,8 +305,7 @@
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"enter": "assistant2::Chat",
|
"enter": "assistant2::Chat",
|
||||||
"cmd-i": "assistant2::ToggleProfileSelector",
|
"cmd-i": "assistant2::ToggleProfileSelector",
|
||||||
"cmd-g d": "git::Diff",
|
"shift-ctrl-r": "assistant2::OpenAssistantDiff"
|
||||||
"shift-escape": "git::ExpandCommitEditor"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -69,6 +69,7 @@ schemars.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
settings.workspace = true
|
settings.workspace = true
|
||||||
|
smallvec.workspace = true
|
||||||
smol.workspace = true
|
smol.workspace = true
|
||||||
streaming_diff.workspace = true
|
streaming_diff.workspace = true
|
||||||
telemetry.workspace = true
|
telemetry.workspace = true
|
||||||
|
|
|
@ -1268,7 +1268,7 @@ impl ActiveThread {
|
||||||
|
|
||||||
let editor_bg = cx.theme().colors().editor_background;
|
let editor_bg = cx.theme().colors().editor_background;
|
||||||
|
|
||||||
div().py_2().child(
|
div().pt_0p5().pb_2().child(
|
||||||
v_flex()
|
v_flex()
|
||||||
.rounded_lg()
|
.rounded_lg()
|
||||||
.border_1()
|
.border_1()
|
||||||
|
|
|
@ -65,6 +65,7 @@ actions!(
|
||||||
RemoveFocusedContext,
|
RemoveFocusedContext,
|
||||||
AcceptSuggestedContext,
|
AcceptSuggestedContext,
|
||||||
OpenActiveThreadAsMarkdown,
|
OpenActiveThreadAsMarkdown,
|
||||||
|
OpenAssistantDiff,
|
||||||
ToggleKeep,
|
ToggleKeep,
|
||||||
Reject,
|
Reject,
|
||||||
RejectAll,
|
RejectAll,
|
||||||
|
|
|
@ -471,6 +471,7 @@ impl Item for AssistantDiff {
|
||||||
impl Render for AssistantDiff {
|
impl Render for AssistantDiff {
|
||||||
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 is_empty = self.multibuffer.read(cx).is_empty();
|
let is_empty = self.multibuffer.read(cx).is_empty();
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.track_focus(&self.focus_handle)
|
.track_focus(&self.focus_handle)
|
||||||
.key_context(if is_empty {
|
.key_context(if is_empty {
|
||||||
|
@ -503,16 +504,17 @@ fn render_diff_hunk_controls(
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> AnyElement {
|
) -> AnyElement {
|
||||||
let editor = assistant_diff.read(cx).editor.clone();
|
let editor = assistant_diff.read(cx).editor.clone();
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.h(line_height)
|
.h(line_height)
|
||||||
.mr_1()
|
.mr_0p5()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
.px_0p5()
|
.px_0p5()
|
||||||
.pb_1()
|
.pb_1()
|
||||||
.border_x_1()
|
.border_x_1()
|
||||||
.border_b_1()
|
.border_b_1()
|
||||||
.border_color(cx.theme().colors().border_variant)
|
.border_color(cx.theme().colors().border)
|
||||||
.rounded_b_lg()
|
.rounded_b_md()
|
||||||
.bg(cx.theme().colors().editor_background)
|
.bg(cx.theme().colors().editor_background)
|
||||||
.gap_1()
|
.gap_1()
|
||||||
.occlude()
|
.occlude()
|
||||||
|
@ -520,24 +522,16 @@ fn render_diff_hunk_controls(
|
||||||
.children(if status.has_secondary_hunk() {
|
.children(if status.has_secondary_hunk() {
|
||||||
vec![
|
vec![
|
||||||
Button::new("reject", "Reject")
|
Button::new("reject", "Reject")
|
||||||
.key_binding(KeyBinding::for_action_in(
|
.disabled(is_created_file)
|
||||||
&crate::Reject,
|
.key_binding(
|
||||||
&editor.read(cx).focus_handle(cx),
|
KeyBinding::for_action_in(
|
||||||
window,
|
&crate::Reject,
|
||||||
cx,
|
&editor.read(cx).focus_handle(cx),
|
||||||
))
|
window,
|
||||||
.tooltip({
|
cx,
|
||||||
let focus_handle = editor.focus_handle(cx);
|
)
|
||||||
move |window, cx| {
|
.map(|kb| kb.size(rems_from_px(12.))),
|
||||||
Tooltip::for_action_in(
|
)
|
||||||
"Reject Hunk",
|
|
||||||
&crate::Reject,
|
|
||||||
&focus_handle,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.on_click({
|
.on_click({
|
||||||
let editor = editor.clone();
|
let editor = editor.clone();
|
||||||
move |_event, window, cx| {
|
move |_event, window, cx| {
|
||||||
|
@ -547,27 +541,17 @@ fn render_diff_hunk_controls(
|
||||||
editor.restore_hunks_in_ranges(vec![point..point], window, cx);
|
editor.restore_hunks_in_ranges(vec![point..point], window, cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
.disabled(is_created_file),
|
|
||||||
Button::new(("keep", row as u64), "Keep")
|
Button::new(("keep", row as u64), "Keep")
|
||||||
.key_binding(KeyBinding::for_action_in(
|
.key_binding(
|
||||||
&crate::ToggleKeep,
|
KeyBinding::for_action_in(
|
||||||
&editor.read(cx).focus_handle(cx),
|
&crate::ToggleKeep,
|
||||||
window,
|
&editor.read(cx).focus_handle(cx),
|
||||||
cx,
|
window,
|
||||||
))
|
cx,
|
||||||
.tooltip({
|
)
|
||||||
let focus_handle = editor.focus_handle(cx);
|
.map(|kb| kb.size(rems_from_px(12.))),
|
||||||
move |window, cx| {
|
)
|
||||||
Tooltip::for_action_in(
|
|
||||||
"Keep Hunk",
|
|
||||||
&crate::ToggleKeep,
|
|
||||||
&focus_handle,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.on_click({
|
.on_click({
|
||||||
let assistant_diff = assistant_diff.clone();
|
let assistant_diff = assistant_diff.clone();
|
||||||
move |_event, _window, cx| {
|
move |_event, _window, cx| {
|
||||||
|
@ -583,12 +567,12 @@ fn render_diff_hunk_controls(
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
vec![Button::new(("review", row as u64), "Review")
|
vec![Button::new(("review", row as u64), "Review")
|
||||||
.tooltip({
|
.key_binding(KeyBinding::for_action_in(
|
||||||
let focus_handle = editor.focus_handle(cx);
|
&ToggleKeep,
|
||||||
move |window, cx| {
|
&editor.read(cx).focus_handle(cx),
|
||||||
Tooltip::for_action_in("Review", &ToggleKeep, &focus_handle, window, cx)
|
window,
|
||||||
}
|
cx,
|
||||||
})
|
))
|
||||||
.on_click({
|
.on_click({
|
||||||
let assistant_diff = assistant_diff.clone();
|
let assistant_diff = assistant_diff.clone();
|
||||||
move |_event, _window, cx| {
|
move |_event, _window, cx| {
|
||||||
|
@ -752,16 +736,21 @@ impl ToolbarItemView for AssistantDiffToolbar {
|
||||||
|
|
||||||
impl Render for AssistantDiffToolbar {
|
impl Render for AssistantDiffToolbar {
|
||||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
if self.assistant_diff(cx).is_none() {
|
let assistant_diff = match self.assistant_diff(cx) {
|
||||||
|
Some(ad) => ad,
|
||||||
|
None => return div(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_empty = assistant_diff.read(cx).multibuffer.read(cx).is_empty();
|
||||||
|
|
||||||
|
if is_empty {
|
||||||
return div();
|
return div();
|
||||||
}
|
}
|
||||||
|
|
||||||
h_group_xl()
|
h_group_xl()
|
||||||
.my_neg_1()
|
.my_neg_1()
|
||||||
.items_center()
|
.items_center()
|
||||||
.py_1()
|
.p_1()
|
||||||
.pl_2()
|
|
||||||
.pr_1()
|
|
||||||
.flex_wrap()
|
.flex_wrap()
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.child(
|
.child(
|
||||||
|
|
|
@ -39,8 +39,8 @@ use crate::thread::{Thread, ThreadError, ThreadId};
|
||||||
use crate::thread_history::{PastContext, PastThread, ThreadHistory};
|
use crate::thread_history::{PastContext, PastThread, ThreadHistory};
|
||||||
use crate::thread_store::ThreadStore;
|
use crate::thread_store::ThreadStore;
|
||||||
use crate::{
|
use crate::{
|
||||||
InlineAssistant, NewPromptEditor, NewThread, OpenActiveThreadAsMarkdown, OpenConfiguration,
|
AssistantDiff, InlineAssistant, NewPromptEditor, NewThread, OpenActiveThreadAsMarkdown,
|
||||||
OpenHistory,
|
OpenAssistantDiff, OpenConfiguration, OpenHistory,
|
||||||
};
|
};
|
||||||
|
|
||||||
action_with_deprecated_aliases!(
|
action_with_deprecated_aliases!(
|
||||||
|
@ -90,6 +90,14 @@ pub fn init(cx: &mut App) {
|
||||||
workspace.focus_panel::<AssistantPanel>(window, cx);
|
workspace.focus_panel::<AssistantPanel>(window, cx);
|
||||||
panel.update(cx, |panel, cx| panel.open_configuration(window, cx));
|
panel.update(cx, |panel, cx| panel.open_configuration(window, cx));
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.register_action(|workspace, _: &OpenAssistantDiff, window, cx| {
|
||||||
|
if let Some(panel) = workspace.panel::<AssistantPanel>(cx) {
|
||||||
|
workspace.focus_panel::<AssistantPanel>(window, cx);
|
||||||
|
panel.update(cx, |panel, cx| {
|
||||||
|
panel.open_assistant_diff(&OpenAssistantDiff, window, cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -432,6 +440,16 @@ impl AssistantPanel {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn open_assistant_diff(
|
||||||
|
&mut self,
|
||||||
|
_: &OpenAssistantDiff,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
|
let thread = self.thread.read(cx).thread().clone();
|
||||||
|
AssistantDiff::deploy(thread, self.workspace.clone(), window, cx).log_err();
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn open_configuration(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
pub(crate) fn open_configuration(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
let context_server_manager = self.thread_store.read(cx).context_server_manager();
|
let context_server_manager = self.thread_store.read(cx).context_server_manager();
|
||||||
let tools = self.thread_store.read(cx).tools();
|
let tools = self.thread_store.read(cx).tools();
|
||||||
|
@ -1105,6 +1123,7 @@ impl Render for AssistantPanel {
|
||||||
}))
|
}))
|
||||||
.on_action(cx.listener(Self::open_active_thread_as_markdown))
|
.on_action(cx.listener(Self::open_active_thread_as_markdown))
|
||||||
.on_action(cx.listener(Self::deploy_prompt_library))
|
.on_action(cx.listener(Self::deploy_prompt_library))
|
||||||
|
.on_action(cx.listener(Self::open_assistant_diff))
|
||||||
.child(self.render_toolbar(window, cx))
|
.child(self.render_toolbar(window, cx))
|
||||||
.map(|parent| match self.active_view {
|
.map(|parent| match self.active_view {
|
||||||
ActiveView::Thread => parent
|
ActiveView::Thread => parent
|
||||||
|
|
|
@ -6,8 +6,8 @@ use editor::{ContextMenuOptions, ContextMenuPlacement, Editor, EditorElement, Ed
|
||||||
use file_icons::FileIcons;
|
use file_icons::FileIcons;
|
||||||
use fs::Fs;
|
use fs::Fs;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
Animation, AnimationExt, App, DismissEvent, Entity, Focusable, Subscription, TextStyle,
|
linear_color_stop, linear_gradient, point, Animation, AnimationExt, App, DismissEvent, Entity,
|
||||||
WeakEntity,
|
Focusable, Subscription, TextStyle, WeakEntity,
|
||||||
};
|
};
|
||||||
use language_model::LanguageModelRegistry;
|
use language_model::LanguageModelRegistry;
|
||||||
use language_model_selector::ToggleModelSelector;
|
use language_model_selector::ToggleModelSelector;
|
||||||
|
@ -31,8 +31,8 @@ use crate::profile_selector::ProfileSelector;
|
||||||
use crate::thread::{RequestKind, Thread};
|
use crate::thread::{RequestKind, Thread};
|
||||||
use crate::thread_store::ThreadStore;
|
use crate::thread_store::ThreadStore;
|
||||||
use crate::{
|
use crate::{
|
||||||
AssistantDiff, Chat, ChatMode, RemoveAllContext, ThreadEvent, ToggleContextPicker,
|
AssistantDiff, Chat, ChatMode, OpenAssistantDiff, RemoveAllContext, ThreadEvent,
|
||||||
ToggleProfileSelector,
|
ToggleContextPicker, ToggleProfileSelector,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct MessageEditor {
|
pub struct MessageEditor {
|
||||||
|
@ -331,7 +331,11 @@ impl Render for MessageEditor {
|
||||||
let action_log = self.thread.read(cx).action_log();
|
let action_log = self.thread.read(cx).action_log();
|
||||||
let changed_buffers = action_log.read(cx).changed_buffers(cx);
|
let changed_buffers = action_log.read(cx).changed_buffers(cx);
|
||||||
let changed_buffers_count = changed_buffers.len();
|
let changed_buffers_count = changed_buffers.len();
|
||||||
|
|
||||||
let editor_bg_color = cx.theme().colors().editor_background;
|
let editor_bg_color = cx.theme().colors().editor_background;
|
||||||
|
let border_color = cx.theme().colors().border;
|
||||||
|
let active_color = cx.theme().colors().element_selected;
|
||||||
|
let bg_edit_files_disclosure = editor_bg_color.blend(active_color.opacity(0.3));
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
.size_full()
|
.size_full()
|
||||||
|
@ -397,18 +401,27 @@ impl Render for MessageEditor {
|
||||||
parent.child(
|
parent.child(
|
||||||
v_flex()
|
v_flex()
|
||||||
.mx_2()
|
.mx_2()
|
||||||
.bg(cx.theme().colors().element_background)
|
.bg(bg_edit_files_disclosure)
|
||||||
.border_1()
|
.border_1()
|
||||||
.border_b_0()
|
.border_b_0()
|
||||||
.border_color(cx.theme().colors().border)
|
.border_color(border_color)
|
||||||
.rounded_t_md()
|
.rounded_t_md()
|
||||||
|
.shadow(smallvec::smallvec![gpui::BoxShadow {
|
||||||
|
color: gpui::black().opacity(0.15),
|
||||||
|
offset: point(px(1.), px(-1.)),
|
||||||
|
blur_radius: px(3.),
|
||||||
|
spread_radius: px(0.),
|
||||||
|
}])
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.p_2()
|
.p_1p5()
|
||||||
.justify_between()
|
.justify_between()
|
||||||
|
.when(self.edits_expanded, |this| {
|
||||||
|
this.border_b_1().border_color(border_color)
|
||||||
|
})
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.gap_2()
|
.gap_1()
|
||||||
.child(
|
.child(
|
||||||
Disclosure::new(
|
Disclosure::new(
|
||||||
"edits-disclosure",
|
"edits-disclosure",
|
||||||
|
@ -423,7 +436,7 @@ impl Render for MessageEditor {
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Label::new("Edits")
|
Label::new("Edits")
|
||||||
.size(LabelSize::XSmall)
|
.size(LabelSize::Small)
|
||||||
.color(Color::Muted),
|
.color(Color::Muted),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
@ -441,13 +454,22 @@ impl Render for MessageEditor {
|
||||||
"files"
|
"files"
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
.size(LabelSize::XSmall)
|
.size(LabelSize::Small)
|
||||||
.color(Color::Muted),
|
.color(Color::Muted),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("review", "Review")
|
Button::new("review", "Review Changes")
|
||||||
.label_size(LabelSize::XSmall)
|
.label_size(LabelSize::Small)
|
||||||
|
.key_binding(
|
||||||
|
KeyBinding::for_action_in(
|
||||||
|
&OpenAssistantDiff,
|
||||||
|
&focus_handle,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.map(|kb| kb.size(rems_from_px(12.))),
|
||||||
|
)
|
||||||
.on_click(cx.listener(|this, _, window, cx| {
|
.on_click(cx.listener(|this, _, window, cx| {
|
||||||
this.handle_review_click(window, cx)
|
this.handle_review_click(window, cx)
|
||||||
})),
|
})),
|
||||||
|
@ -474,50 +496,94 @@ impl Render for MessageEditor {
|
||||||
std::path::MAIN_SEPARATOR_STR
|
std::path::MAIN_SEPARATOR_STR
|
||||||
))
|
))
|
||||||
.color(Color::Muted)
|
.color(Color::Muted)
|
||||||
.size(LabelSize::Small),
|
.size(LabelSize::XSmall)
|
||||||
|
.buffer_font(cx),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let name_label = path.file_name().map(|name| {
|
let name_label = path.file_name().map(|name| {
|
||||||
Label::new(name.to_string_lossy().to_string())
|
Label::new(name.to_string_lossy().to_string())
|
||||||
.size(LabelSize::Small)
|
.size(LabelSize::XSmall)
|
||||||
|
.buffer_font(cx)
|
||||||
});
|
});
|
||||||
|
|
||||||
let file_icon = FileIcons::get_icon(&path, cx)
|
let file_icon = FileIcons::get_icon(&path, cx)
|
||||||
.map(Icon::from_path)
|
.map(Icon::from_path)
|
||||||
.unwrap_or_else(|| Icon::new(IconName::File));
|
.map(|icon| {
|
||||||
|
icon.color(Color::Muted).size(IconSize::Small)
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
Icon::new(IconName::File)
|
||||||
|
.color(Color::Muted)
|
||||||
|
.size(IconSize::Small)
|
||||||
|
});
|
||||||
|
|
||||||
let element = div()
|
let element = div()
|
||||||
.p_2()
|
.relative()
|
||||||
|
.py_1()
|
||||||
|
.px_2()
|
||||||
.when(index + 1 < changed_buffers_count, |parent| {
|
.when(index + 1 < changed_buffers_count, |parent| {
|
||||||
parent
|
parent.border_color(border_color).border_b_1()
|
||||||
.border_color(cx.theme().colors().border)
|
|
||||||
.border_b_1()
|
|
||||||
})
|
})
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.child(file_icon)
|
.justify_between()
|
||||||
.child(
|
.child(
|
||||||
// TODO: handle overflow
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.children(parent_label)
|
.id("file-container")
|
||||||
.children(name_label),
|
.pr_8()
|
||||||
)
|
.gap_1p5()
|
||||||
// TODO: show lines changed
|
.max_w_full()
|
||||||
.child(
|
.overflow_x_scroll()
|
||||||
Label::new("+").color(Color::Created),
|
.child(file_icon)
|
||||||
)
|
.child(
|
||||||
.child(
|
h_flex()
|
||||||
Label::new("-").color(Color::Deleted),
|
.children(parent_label)
|
||||||
|
.children(name_label),
|
||||||
|
) // TODO: show lines changed
|
||||||
|
.child(
|
||||||
|
Label::new("+")
|
||||||
|
.color(Color::Created),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Label::new("-")
|
||||||
|
.color(Color::Deleted),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.when(!changed.needs_review, |parent| {
|
.when(!changed.needs_review, |parent| {
|
||||||
parent.child(
|
parent.child(
|
||||||
Icon::new(IconName::Check)
|
Icon::new(IconName::Check)
|
||||||
.color(Color::Success),
|
.color(Color::Success),
|
||||||
)
|
)
|
||||||
}),
|
})
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.h_full()
|
||||||
|
.absolute()
|
||||||
|
.w_8()
|
||||||
|
.bottom_0()
|
||||||
|
.map(|this| {
|
||||||
|
if !changed.needs_review {
|
||||||
|
this.right_4()
|
||||||
|
} else {
|
||||||
|
this.right_0()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.bg(linear_gradient(
|
||||||
|
90.,
|
||||||
|
linear_color_stop(
|
||||||
|
editor_bg_color,
|
||||||
|
1.,
|
||||||
|
),
|
||||||
|
linear_color_stop(
|
||||||
|
editor_bg_color
|
||||||
|
.opacity(0.2),
|
||||||
|
0.,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Some(element)
|
Some(element)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue