ssh: Add tweaks to the UI (#18817)

Follow up to https://github.com/zed-industries/zed/pull/18727

---

Release Notes:

- N/A
This commit is contained in:
Danilo Leal 2024-10-08 19:32:52 +02:00 committed by GitHub
parent 3f2de172ae
commit af9a595770
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 122 additions and 82 deletions

View file

@ -556,23 +556,28 @@ impl DevServerProjects {
.w_full() .w_full()
.border_l_1() .border_l_1()
.border_color(cx.theme().colors().border_variant) .border_color(cx.theme().colors().border_variant)
.my_1() .mb_1()
.mx_1p5() .mx_1p5()
.py_0p5() .pl_2()
.px_3()
.child( .child(
List::new() List::new()
.empty_message("No projects.") .empty_message("No projects.")
.children(ssh_connection.projects.iter().enumerate().map(|(pix, p)| { .children(ssh_connection.projects.iter().enumerate().map(|(pix, p)| {
self.render_ssh_project(ix, &ssh_connection, pix, p, cx) v_flex().gap_0p5().child(self.render_ssh_project(
ix,
&ssh_connection,
pix,
p,
cx,
))
})) }))
.child( .child(
h_flex().child( h_flex().mt_1().pl_1().child(
Button::new("new-remote_project", "Open Folder…") Button::new("new-remote_project", "Open Folder…")
.icon(IconName::Plus)
.size(ButtonSize::Default) .size(ButtonSize::Default)
.style(ButtonStyle::Filled)
.layer(ElevationIndex::ModalSurface) .layer(ElevationIndex::ModalSurface)
.icon(IconName::Plus)
.icon_color(Color::Muted)
.icon_position(IconPosition::Start) .icon_position(IconPosition::Start)
.on_click(cx.listener(move |this, _, cx| { .on_click(cx.listener(move |this, _, cx| {
this.create_ssh_project(ix, ssh_connection.clone(), cx); this.create_ssh_project(ix, ssh_connection.clone(), cx);
@ -593,9 +598,15 @@ impl DevServerProjects {
) -> impl IntoElement { ) -> impl IntoElement {
let project = project.clone(); let project = project.clone();
let server = server.clone(); let server = server.clone();
ListItem::new(("remote-project", ix)) ListItem::new(("remote-project", ix))
.inset(true)
.spacing(ui::ListItemSpacing::Sparse) .spacing(ui::ListItemSpacing::Sparse)
.start_slot(Icon::new(IconName::Folder).color(Color::Muted)) .start_slot(
Icon::new(IconName::Folder)
.color(Color::Muted)
.size(IconSize::Small),
)
.child(Label::new(project.paths.join(", "))) .child(Label::new(project.paths.join(", ")))
.on_click(cx.listener(move |this, _, cx| { .on_click(cx.listener(move |this, _, cx| {
let Some(app_state) = this let Some(app_state) = this
@ -635,7 +646,7 @@ impl DevServerProjects {
.on_click( .on_click(
cx.listener(move |this, _, cx| this.delete_ssh_project(server_ix, ix, cx)), cx.listener(move |this, _, cx| this.delete_ssh_project(server_ix, ix, cx)),
) )
.tooltip(|cx| Tooltip::text("Delete remote project", cx)) .tooltip(|cx| Tooltip::text("Delete Remote Project", cx))
.into_any_element(), .into_any_element(),
)) ))
} }
@ -709,6 +720,7 @@ impl DevServerProjects {
}) })
}); });
let theme = cx.theme(); let theme = cx.theme();
v_flex() v_flex()
.id("create-dev-server") .id("create-dev-server")
.overflow_hidden() .overflow_hidden()
@ -763,6 +775,7 @@ impl DevServerProjects {
.child( .child(
h_flex() h_flex()
.bg(theme.colors().editor_background) .bg(theme.colors().editor_background)
.rounded_b_md()
.w_full() .w_full()
.map(|this| { .map(|this| {
if let Some(ssh_prompt) = ssh_prompt { if let Some(ssh_prompt) = ssh_prompt {
@ -773,9 +786,8 @@ impl DevServerProjects {
h_flex() h_flex()
.p_2() .p_2()
.w_full() .w_full()
.content_center() .justify_center()
.gap_2() .gap_1p5()
.child(h_flex().w_full())
.child( .child(
div().p_1().rounded_lg().bg(color).with_animation( div().p_1().rounded_lg().bg(color).with_animation(
"pulse-ssh-waiting-for-connection", "pulse-ssh-waiting-for-connection",
@ -788,8 +800,7 @@ impl DevServerProjects {
.child( .child(
Label::new("Waiting for connection…") Label::new("Waiting for connection…")
.size(LabelSize::Small), .size(LabelSize::Small),
) ),
.child(h_flex().w_full()),
) )
} }
}), }),

View file

@ -566,7 +566,7 @@ impl PickerDelegate for RecentProjectsDelegate {
.border_t_1() .border_t_1()
.py_2() .py_2()
.pr_2() .pr_2()
.border_color(cx.theme().colors().border) .border_color(cx.theme().colors().border_variant)
.justify_end() .justify_end()
.gap_4() .gap_4()
.child( .child(
@ -574,7 +574,7 @@ impl PickerDelegate for RecentProjectsDelegate {
.when_some(KeyBinding::for_action(&OpenRemote, cx), |button, key| { .when_some(KeyBinding::for_action(&OpenRemote, cx), |button, key| {
button.child(key) button.child(key)
}) })
.child(Label::new("Open remote folder…").color(Color::Muted)) .child(Label::new("Open Remote Folder…").color(Color::Muted))
.on_click(|_, cx| cx.dispatch_action(OpenRemote.boxed_clone())), .on_click(|_, cx| cx.dispatch_action(OpenRemote.boxed_clone())),
) )
.child( .child(
@ -583,7 +583,7 @@ impl PickerDelegate for RecentProjectsDelegate {
KeyBinding::for_action(&workspace::Open, cx), KeyBinding::for_action(&workspace::Open, cx),
|button, key| button.child(key), |button, key| button.child(key),
) )
.child(Label::new("Open local folder…").color(Color::Muted)) .child(Label::new("Open Local Folder…").color(Color::Muted))
.on_click(|_, cx| cx.dispatch_action(workspace::Open.boxed_clone())), .on_click(|_, cx| cx.dispatch_action(workspace::Open.boxed_clone())),
) )
.into_any(), .into_any(),

View file

@ -16,9 +16,9 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources}; use settings::{Settings, SettingsSources};
use ui::{ use ui::{
div, h_flex, v_flex, ActiveTheme, ButtonCommon, Clickable, Color, FluentBuilder as _, Icon, div, h_flex, prelude::*, v_flex, ActiveTheme, ButtonCommon, Clickable, Color, Icon, IconButton,
IconButton, IconName, IconSize, InteractiveElement, IntoElement, Label, LabelCommon, Styled, IconName, IconSize, InteractiveElement, IntoElement, Label, LabelCommon, Styled, Tooltip,
StyledExt as _, Tooltip, ViewContext, VisualContext, WindowContext, ViewContext, VisualContext, WindowContext,
}; };
use workspace::{AppState, ModalView, Workspace}; use workspace::{AppState, ModalView, Workspace};
@ -84,6 +84,7 @@ pub struct SshPrompt {
pub struct SshConnectionModal { pub struct SshConnectionModal {
pub(crate) prompt: View<SshPrompt>, pub(crate) prompt: View<SshPrompt>,
} }
impl SshPrompt { impl SshPrompt {
pub fn new(connection_options: &SshConnectionOptions, cx: &mut ViewContext<Self>) -> Self { pub fn new(connection_options: &SshConnectionOptions, cx: &mut ViewContext<Self>) -> Self {
let connection_string = connection_options.connection_string().into(); let connection_string = connection_options.connection_string().into();
@ -136,20 +137,18 @@ impl SshPrompt {
} }
impl Render for SshPrompt { impl Render for SshPrompt {
fn render(&mut self, _: &mut ViewContext<Self>) -> impl IntoElement { fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let cx = cx.window_context();
let theme = cx.theme();
v_flex() v_flex()
.w_full()
.key_context("PasswordPrompt") .key_context("PasswordPrompt")
.justify_start()
.child(
v_flex()
.p_4()
.size_full() .size_full()
.justify_center()
.child( .child(
h_flex() h_flex()
.gap_2() .py_2()
.justify_between() .px_4()
.child(h_flex().w_full()) .justify_center()
.child(if self.error_message.is_some() { .child(if self.error_message.is_some() {
Icon::new(IconName::XCircle) Icon::new(IconName::XCircle)
.size(IconSize::Medium) .size(IconSize::Medium)
@ -162,31 +161,46 @@ impl Render for SshPrompt {
"arrow-circle", "arrow-circle",
Animation::new(Duration::from_secs(2)).repeat(), Animation::new(Duration::from_secs(2)).repeat(),
|icon, delta| { |icon, delta| {
icon.transform(Transformation::rotate(percentage( icon.transform(Transformation::rotate(percentage(delta)))
delta,
)))
}, },
) )
.into_any_element() .into_any_element()
}) })
.child(Label::new(format!( .child(
"Connecting to {}…", div()
self.connection_string .ml_1()
))) .child(Label::new("SSH Connection").size(LabelSize::Small)),
.child(h_flex().w_full()),
) )
.child(
div()
.when_some(self.error_message.as_ref(), |el, error| { .when_some(self.error_message.as_ref(), |el, error| {
el.child(Label::new(error.clone())) el.child(Label::new(format!("{}", error)).size(LabelSize::Small))
}) })
.when( .when(
self.error_message.is_none() && self.status_message.is_some(), self.error_message.is_none() && self.status_message.is_some(),
|el| el.child(Label::new(self.status_message.clone().unwrap())), |el| {
el.child(
Label::new(format!(
"{}",
self.status_message.clone().unwrap()
))
.size(LabelSize::Small),
) )
.when_some(self.prompt.as_ref(), |el, prompt| { },
el.child(Label::new(prompt.0.clone())) ),
.child(self.editor.clone()) ),
}),
) )
.child(div().when_some(self.prompt.as_ref(), |el, prompt| {
el.child(
h_flex()
.p_4()
.border_t_1()
.border_color(theme.colors().border_variant)
.font_buffer(cx)
.child(Label::new(prompt.0.clone()))
.child(self.editor.clone()),
)
}))
} }
} }
@ -210,39 +224,54 @@ impl Render for SshConnectionModal {
fn render(&mut self, cx: &mut ui::ViewContext<Self>) -> impl ui::IntoElement { fn render(&mut self, cx: &mut ui::ViewContext<Self>) -> impl ui::IntoElement {
let connection_string = self.prompt.read(cx).connection_string.clone(); let connection_string = self.prompt.read(cx).connection_string.clone();
let theme = cx.theme(); let theme = cx.theme();
let header_color = theme.colors().element_background; let mut header_color = cx.theme().colors().text;
let body_color = theme.colors().background; header_color.fade_out(0.96);
let body_color = theme.colors().editor_background;
v_flex() v_flex()
.elevation_3(cx) .elevation_3(cx)
.on_action(cx.listener(Self::dismiss)) .on_action(cx.listener(Self::dismiss))
.on_action(cx.listener(Self::confirm)) .on_action(cx.listener(Self::confirm))
.w(px(400.)) .w(px(500.))
.border_1()
.border_color(theme.colors().border)
.child( .child(
h_flex() h_flex()
.relative()
.p_1() .p_1()
.rounded_t_md()
.border_b_1() .border_b_1()
.border_color(theme.colors().border) .border_color(theme.colors().border)
.bg(header_color) .bg(header_color)
.justify_between() .justify_between()
.child( .child(
div().absolute().left_0p5().top_0p5().child(
IconButton::new("ssh-connection-cancel", IconName::ArrowLeft) IconButton::new("ssh-connection-cancel", IconName::ArrowLeft)
.icon_size(IconSize::XSmall) .icon_size(IconSize::XSmall)
.on_click(|_, cx| cx.dispatch_action(menu::Cancel.boxed_clone())) .on_click(|_, cx| cx.dispatch_action(menu::Cancel.boxed_clone()))
.tooltip(|cx| Tooltip::for_action("Back", &menu::Cancel, cx)), .tooltip(|cx| Tooltip::for_action("Back", &menu::Cancel, cx)),
),
) )
.child( .child(
h_flex() h_flex()
.w_full()
.gap_2() .gap_2()
.justify_center()
.child(Icon::new(IconName::Server).size(IconSize::XSmall)) .child(Icon::new(IconName::Server).size(IconSize::XSmall))
.child( .child(
Label::new(connection_string) Label::new(connection_string)
.size(ui::LabelSize::Small) .size(ui::LabelSize::Small)
.single_line(), .single_line(),
), ),
),
) )
.child(div()), .child(
h_flex()
.rounded_b_md()
.bg(body_color)
.w_full()
.child(self.prompt.clone()),
) )
.child(h_flex().bg(body_color).w_full().child(self.prompt.clone()))
} }
} }

View file

@ -24,8 +24,8 @@ use smallvec::SmallVec;
use std::sync::Arc; use std::sync::Arc;
use theme::ActiveTheme; use theme::ActiveTheme;
use ui::{ use ui::{
h_flex, prelude::*, Avatar, Button, ButtonLike, ButtonStyle, ContextMenu, Icon, IconName, h_flex, prelude::*, Avatar, Button, ButtonLike, ButtonStyle, ContextMenu, Icon,
Indicator, PopoverMenu, Tooltip, IconButtonShape, IconName, IconSize, Indicator, PopoverMenu, Tooltip,
}; };
use util::ResultExt; use util::ResultExt;
use vcs_menu::{BranchList, OpenRecent as ToggleVcsMenu}; use vcs_menu::{BranchList, OpenRecent as ToggleVcsMenu};
@ -274,18 +274,19 @@ impl TitleBar {
}; };
let indicator = div() let indicator = div()
.absolute() .absolute()
.w_1_4() .size_1p5()
.h_1_4()
.right_0p5() .right_0p5()
.bottom_0p5() .bottom_0p5()
.p_1() .rounded_full()
.rounded_2xl()
.bg(indicator_color.color(cx)); .bg(indicator_color.color(cx));
Some( Some(
div() div()
.relative()
.child( .child(
IconButton::new("ssh-server-icon", IconName::Server) IconButton::new("ssh-server-icon", IconName::Server)
.icon_size(IconSize::Small)
.shape(IconButtonShape::Square)
.tooltip(move |cx| { .tooltip(move |cx| {
Tooltip::with_meta( Tooltip::with_meta(
"Remote Project", "Remote Project",
@ -294,7 +295,6 @@ impl TitleBar {
cx, cx,
) )
}) })
.shape(ui::IconButtonShape::Square)
.on_click(|_, cx| { .on_click(|_, cx| {
cx.dispatch_action(OpenRemote.boxed_clone()); cx.dispatch_action(OpenRemote.boxed_clone());
}), }),