modal: Improve paddings and gap in Modal. (#1153)

This commit is contained in:
Jason Lee 2025-08-19 11:41:12 +08:00 committed by GitHub
parent 6ae7558c44
commit 8e525c6c99
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 73 additions and 65 deletions

View file

@ -1,6 +1,6 @@
use gpui::{ use gpui::{
div, prelude::FluentBuilder as _, px, App, AppContext, Context, Entity, FocusHandle, Focusable, div, px, App, AppContext, Context, Entity, FocusHandle, Focusable, InteractiveElement as _,
InteractiveElement as _, IntoElement, ParentElement, Render, SharedString, Styled, Window, IntoElement, ParentElement, Render, SharedString, Styled, Window,
}; };
use gpui_component::{ use gpui_component::{
@ -12,7 +12,7 @@ use gpui_component::{
input::{InputState, TextInput}, input::{InputState, TextInput},
modal::ModalButtonProps, modal::ModalButtonProps,
text::TextView, text::TextView,
v_flex, ActiveTheme, ContextModal as _, v_flex, ActiveTheme, ContextModal as _, Icon, IconName,
}; };
use crate::{section, TestAction}; use crate::{section, TestAction};
@ -26,7 +26,6 @@ pub struct ModalStory {
dropdown: Entity<DropdownState<Vec<String>>>, dropdown: Entity<DropdownState<Vec<String>>>,
modal_overlay: bool, modal_overlay: bool,
model_show_close: bool, model_show_close: bool,
model_padding: bool,
model_keyboard: bool, model_keyboard: bool,
overlay_closable: bool, overlay_closable: bool,
} }
@ -78,7 +77,6 @@ impl ModalStory {
dropdown, dropdown,
modal_overlay: true, modal_overlay: true,
model_show_close: true, model_show_close: true,
model_padding: true,
model_keyboard: true, model_keyboard: true,
overlay_closable: true, overlay_closable: true,
} }
@ -87,7 +85,6 @@ impl ModalStory {
fn show_modal(&mut self, window: &mut Window, cx: &mut Context<Self>) { fn show_modal(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let overlay = self.modal_overlay; let overlay = self.modal_overlay;
let modal_show_close = self.model_show_close; let modal_show_close = self.model_show_close;
let modal_padding = self.model_padding;
let overlay_closable = self.overlay_closable; let overlay_closable = self.overlay_closable;
let input1 = self.input1.clone(); let input1 = self.input1.clone();
let date = self.date.clone(); let date = self.date.clone();
@ -102,7 +99,6 @@ impl ModalStory {
.keyboard(keyboard) .keyboard(keyboard)
.show_close(modal_show_close) .show_close(modal_show_close)
.overlay_closable(overlay_closable) .overlay_closable(overlay_closable)
.when(!modal_padding, |this| this.p(px(0.)))
.child( .child(
v_flex() v_flex()
.gap_3() .gap_3()
@ -148,7 +144,6 @@ impl ModalStory {
.keyboard(keyboard) .keyboard(keyboard)
.show_close(modal_show_close) .show_close(modal_show_close)
.overlay_closable(overlay_closable) .overlay_closable(overlay_closable)
.when(!modal_padding, |this| this.p(px(0.)))
}); });
}, },
), ),
@ -225,15 +220,6 @@ impl Render for ModalStory {
cx.notify(); cx.notify();
})), })),
) )
.child(
Checkbox::new("modal-padding")
.label("Model Padding")
.checked(self.model_padding)
.on_click(cx.listener(|view, _, _, cx| {
view.model_padding = !view.model_padding;
cx.notify();
})),
)
.child( .child(
Checkbox::new("modal-keyboard") Checkbox::new("modal-keyboard")
.label("Keyboard") .label("Keyboard")
@ -307,31 +293,34 @@ impl Render for ModalStory {
.outline() .outline()
.label("Custom Buttons") .label("Custom Buttons")
.on_click(cx.listener(move |_, _, window, cx| { .on_click(cx.listener(move |_, _, window, cx| {
window.open_modal(cx, move |modal, _, _| { window.open_modal(cx, move |modal, _, cx| {
modal modal
.rounded_lg() .rounded_lg()
.p_3()
.confirm() .confirm()
.overlay(modal_overlay) .overlay(modal_overlay)
.overlay_closable(overlay_closable) .overlay_closable(overlay_closable)
.child("Are you sure to delete this item?") .child(
h_flex().gap_3()
.child(Icon::new(IconName::TriangleAlert).size_6().text_color(cx.theme().warning))
.child("Update successful, we need to restart the application.")
)
.button_props( .button_props(
ModalButtonProps::default() ModalButtonProps::default()
.cancel_text("Abort") .cancel_text("Later")
.cancel_variant(ButtonVariant::Secondary) .cancel_variant(ButtonVariant::Secondary)
.ok_text("Sure") .ok_text("Restart Now")
.ok_variant(ButtonVariant::Danger), .ok_variant(ButtonVariant::Danger),
) )
.on_ok(|_, window, cx| { .on_ok(|_, window, cx| {
window.push_notification( window.push_notification(
"You have pressed sure.", "You have pressed restart.",
cx, cx,
); );
true true
}) })
.on_cancel(|_, window, cx| { .on_cancel(|_, window, cx| {
window.push_notification( window.push_notification(
"You have pressed abort.", "You have pressed later.",
cx, cx,
); );
true true
@ -382,7 +371,22 @@ impl Render for ModalStory {
), ),
) )
.child( .child(
section("Custom Modal style").child( section("Custom Paddings").child(
Button::new("custom-modal-paddings")
.outline()
.label("Custom Paddings")
.on_click(cx.listener(move |_, _, window, cx| {
window.open_modal(cx, move |modal, _, _| {
modal
.p_3()
.title("Custom Modal Title")
.child("This is a custom modal content, we can use paddings to control the layout and spacing within the modal.")
});
})),
),
)
.child(
section("Custom Style").child(
Button::new("custom-modal-style") Button::new("custom-modal-style")
.outline() .outline()
.label("Custom Modal Style") .label("Custom Modal Style")
@ -390,16 +394,10 @@ impl Render for ModalStory {
window.open_modal(cx, move |modal, _, cx| { window.open_modal(cx, move |modal, _, cx| {
modal modal
.rounded_lg() .rounded_lg()
.p_0() .bg(cx.theme().cyan)
.title(div().pt_4().px_4().child("Custom Modal Title")) .text_color(cx.theme().info_foreground)
.child( .title("Custom Modal Title")
div() .child("This is a custom modal content.")
.bg(cx.theme().info)
.text_color(cx.theme().info_foreground)
.p_4()
.rounded_b_lg()
.child("This is a custom modal content."),
)
}); });
})), })),
), ),

View file

@ -2,7 +2,7 @@ use std::{rc::Rc, time::Duration};
use gpui::{ use gpui::{
anchored, div, hsla, point, prelude::FluentBuilder, px, relative, Animation, AnimationExt as _, anchored, div, hsla, point, prelude::FluentBuilder, px, relative, Animation, AnimationExt as _,
AnyElement, App, Axis, Bounds, BoxShadow, ClickEvent, Div, FocusHandle, Hsla, AnyElement, App, Axis, Bounds, BoxShadow, ClickEvent, Div, Edges, FocusHandle, Hsla,
InteractiveElement, IntoElement, KeyBinding, MouseButton, ParentElement, Pixels, Point, InteractiveElement, IntoElement, KeyBinding, MouseButton, ParentElement, Pixels, Point,
RenderOnce, SharedString, StyleRefinement, Styled, Window, RenderOnce, SharedString, StyleRefinement, Styled, Window,
}; };
@ -354,13 +354,21 @@ impl RenderOnce for Modal {
let y = self.margin_top.unwrap_or(view_size.height / 10.) + offset_top; let y = self.margin_top.unwrap_or(view_size.height / 10.) + offset_top;
let x = bounds.center().x - self.width / 2.; let x = bounds.center().x - self.width / 2.;
let mut padding_right = px(24.); let base_size = window.text_style().font_size;
let mut padding_left = px(24.); let rem_size = window.rem_size();
let mut paddings = Edges::all(px(24.));
if let Some(pl) = self.style.padding.left { if let Some(pl) = self.style.padding.left {
padding_left = pl.to_pixels(self.width.into(), window.rem_size()); paddings.left = pl.to_pixels(base_size, rem_size);
} }
if let Some(pr) = self.style.padding.right { if let Some(pr) = self.style.padding.right {
padding_right = pr.to_pixels(self.width.into(), window.rem_size()); paddings.right = pr.to_pixels(base_size, rem_size);
}
if let Some(pt) = self.style.padding.top {
paddings.top = pt.to_pixels(base_size, rem_size);
}
if let Some(pb) = self.style.padding.bottom {
paddings.bottom = pb.to_pixels(base_size, rem_size);
} }
let animation = Animation::new(Duration::from_secs_f64(0.25)) let animation = Animation::new(Duration::from_secs_f64(0.25))
@ -401,8 +409,9 @@ impl RenderOnce for Modal {
.border_color(cx.theme().border) .border_color(cx.theme().border)
.rounded(cx.theme().radius_lg) .rounded(cx.theme().radius_lg)
.min_h_24() .min_h_24()
.py_6() .pt(paddings.top)
.gap_4() .pb(paddings.bottom)
.gap(paddings.top.min(px(16.)))
.refine_style(&self.style) .refine_style(&self.style)
.px_0() .px_0()
.key_context(CONTEXT) .key_context(CONTEXT)
@ -448,46 +457,47 @@ impl RenderOnce for Modal {
.when_some(self.title, |this, title| { .when_some(self.title, |this, title| {
this.child( this.child(
div() div()
.font_semibold() .pl(paddings.left)
.pl(padding_left) .pr(paddings.right)
.pr(padding_right)
.line_height(relative(1.)) .line_height(relative(1.))
.font_semibold()
.child(title), .child(title),
) )
}) })
.when(self.show_close, |this| { .children(self.show_close.then(|| {
this.child( Button::new("close")
Button::new("close") .absolute()
.absolute() .top(paddings.top - px(3.))
.top_4() .right(paddings.right - px(3.))
.right_4() .small()
.small() .ghost()
.ghost() .icon(IconName::Close)
.icon(IconName::Close) .on_click({
.on_click(move |_, window, cx| { let on_cancel = self.on_cancel.clone();
let on_close = self.on_close.clone();
move |_, window, cx| {
on_cancel(&ClickEvent::default(), window, cx); on_cancel(&ClickEvent::default(), window, cx);
on_close(&ClickEvent::default(), window, cx); on_close(&ClickEvent::default(), window, cx);
window.close_modal(cx); window.close_modal(cx);
}), }
) })
}) }))
.child( .child(
div().w_full().flex_1().overflow_hidden().child( div().w_full().flex_1().overflow_hidden().child(
v_flex() v_flex()
.pl(padding_left) .pl(paddings.left)
.pr(padding_right) .pr(paddings.right)
.scrollable(Axis::Vertical) .scrollable(Axis::Vertical)
.child(self.content), .child(self.content),
), ),
) )
.when(self.footer.is_some(), |this| { .when_some(self.footer, |this, footer| {
let footer = self.footer.unwrap();
this.child( this.child(
h_flex() h_flex()
.gap_2() .gap_2()
.pl(padding_left) .pl(paddings.left)
.pr(padding_right) .pr(paddings.right)
.line_height(relative(1.))
.justify_end() .justify_end()
.children(footer(render_ok, render_cancel, window, cx)), .children(footer(render_ok, render_cancel, window, cx)),
) )