Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions src/gui/board/ui_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,54 @@ fn test_board_space_preview_deactivation_hides_preview_in_pinned_window(cx: &mut
});
}

#[gpui_kit::test]
fn test_about_content_centers_in_body_and_update_row(cx: &mut TestAppContext) {
let (handle, board, _) = open_board(cx, vec![]);
cx.update_window(handle, |_, window, cx| {
board.update(cx, |board, _| {
board.update_manager.managed = true;
board.update_manager.status = crate::updater::models::UpdateStatus::UpToDate;
});
window.render_frame(cx);
window.click("about-button", cx);
let body = window.find("about-content").bounds();
let logo = window.find("about-logo").bounds();
let social = window.find("about-social-links").bounds();
let status = window.find("about-update-status").bounds();
let action = window.find("update-check-button").bounds();
assert!((logo.center().x - body.center().x).abs() < gpui_kit::px(1.));
assert!(((status.left() + action.right()) / 2. - body.center().x).abs() < gpui_kit::px(1.));
assert!(
((logo.top() + social.bottom()) / 2. - body.center().y).abs() < gpui_kit::px(1.),
"content must be vertically centered below the header"
);
})
.unwrap();

cx.simulate_window_resize(
handle,
gpui_kit::size(gpui_kit::px(400.), gpui_kit::px(360.)),
);
cx.update_window(handle, |_, window, cx| {
window.render_frame(cx);
let body = window.find("about-content").bounds();
let logo = window.find("about-logo").bounds();
assert!(logo.top() >= body.top(), "overflow must not clip the logo");
window.scroll(
"about-content",
gpui_kit::ScrollDelta::Pixels(gpui_kit::point(gpui_kit::px(0.), gpui_kit::px(-1000.))),
cx,
);
let social = window.find("about-social-links").bounds();
assert!(social.top() >= body.top());
assert!(
social.bottom() <= body.bottom(),
"social links must remain reachable: body {body:?}, social {social:?}"
);
})
.unwrap();
}

#[gpui_kit::test]
fn test_board_controls_expose_localized_accessible_names(cx: &mut TestAppContext) {
let (handle, board, _) = open_board(cx, vec![]);
Expand Down
147 changes: 89 additions & 58 deletions src/gui/panel/about.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use gpui_kit::base::TestSupportExt;
use gpui_kit::{
Context, ImageSource, Resource, StatefulInteractiveElement,
component::{
Expand Down Expand Up @@ -61,71 +62,85 @@ pub(crate) fn render_about_content(
cx,
);

v_flex().size_full().child(header).child(
v_flex().w_full().flex_1().min_h_0().child(header).child(
v_flex()
.id("about-content")
.test_support()
.overflow_y_scroll()
.flex_1()
.items_center()
.gap_3()
// Logo
.min_h_0()
.child(
img(ImageSource::Resource(Resource::Embedded("logo.png".into())))
.w(px(80.0))
.h(px(80.0))
.rounded_md(),
)
// Version text
.child(
div()
.text_sm()
.text_color(cx.theme().foreground)
.font_weight(gpui_kit::FontWeight::MEDIUM)
.child(t!("about_version", version = version)),
)
// Update section
.child(render_update_section(board, cx))
// Description
.child(
div()
.px_8()
.text_center()
.text_sm()
.text_color(cx.theme().foreground)
.child(t!("about_description")),
)
// License
.child(
Button::new("license-button")
.small()
.ghost()
.label(t!("about_license"))
.on_click(|_, _, cx| {
cx.open_url(LICENSE_URL);
}),
)
// Social links with icons
.child(
h_flex()
.gap_2()
.child(render_social_link_button(
"github-button",
Icon::empty().path("icons/github.svg").size(px(32.0)),
t!("about_github_tooltip").into_owned(),
GITHUB_URL,
))
.child(render_social_link_button(
"xiaohongshu-button",
Icon::empty().path("icons/xiaohongshu.svg").size(px(32.0)),
t!("about_xiaohongshu_tooltip").into_owned(),
XIAOHONGSHU_URL,
)),
v_flex()
.w_full()
.flex_shrink_0()
// Auto margins center when space permits without clipping the top on overflow.
.my_auto()
.py_4()
.items_center()
.gap_3()
// Logo
.child(
img(ImageSource::Resource(Resource::Embedded("logo.png".into())))
.id("about-logo")
.test_support()
.w(px(80.0))
.h(px(80.0))
.rounded_md(),
)
// Version text
.child(
div()
.text_sm()
.text_color(cx.theme().foreground)
.font_weight(gpui_kit::FontWeight::MEDIUM)
.child(t!("about_version", version = version)),
)
// Update section
.child(render_update_section(board, cx))
// Description
.child(
div()
.px_8()
.text_center()
.text_sm()
.text_color(cx.theme().foreground)
.child(t!("about_description")),
)
// License
.child(
Button::new("license-button")
.small()
.ghost()
.label(t!("about_license"))
.on_click(|_, _, cx| {
cx.open_url(LICENSE_URL);
}),
)
// Social links with icons
.child(
h_flex()
.id("about-social-links")
.test_support()
.gap_2()
.child(render_social_link_button(
"github-button",
Icon::empty().path("icons/github.svg").size(px(32.0)),
t!("about_github_tooltip").into_owned(),
GITHUB_URL,
))
.child(render_social_link_button(
"xiaohongshu-button",
Icon::empty().path("icons/xiaohongshu.svg").size(px(32.0)),
t!("about_xiaohongshu_tooltip").into_owned(),
XIAOHONGSHU_URL,
)),
),
),
)
}

fn render_update_section(board: &RopyBoard, cx: &Context<'_, RopyBoard>) -> impl IntoElement {
let status_text: gpui_kit::SharedString = match &board.update_manager.status {
fn update_status_text(status: &UpdateStatus) -> gpui_kit::SharedString {
match status {
UpdateStatus::Idle => t!("update_check_now").into(),
UpdateStatus::Checking => t!("update_checking").into(),
UpdateStatus::Available(info) => t!("update_available", version = &info.version).into(),
Expand Down Expand Up @@ -159,7 +174,11 @@ fn render_update_section(board: &RopyBoard, cx: &Context<'_, RopyBoard>) -> impl
crate::updater::errors::UpdateFailure::Release => t!("update_error"),
}
.into(),
};
}
}

fn render_update_section(board: &RopyBoard, cx: &Context<'_, RopyBoard>) -> impl IntoElement {
let status_text = update_status_text(&board.update_manager.status);
// Use `foreground` for every non-error status so the text stays legible
// under dark themes when the window is in transparent mode, where
// `muted_foreground` blends into the translucent background.
Expand Down Expand Up @@ -209,12 +228,24 @@ fn render_update_section(board: &RopyBoard, cx: &Context<'_, RopyBoard>) -> impl
};

v_flex()
.max_w_full()
.px_4()
.items_center()
.text_center()
.gap_2()
.child(
h_flex()
.flex_wrap()
.justify_center()
.gap_2()
.child(div().text_xs().text_color(status_color).child(status_text))
.child(
div()
.id("about-update-status")
.test_support()
.text_xs()
.text_color(status_color)
.child(status_text),
)
.children(action_button),
)
.when(board.update_manager.managed, |this| {
Expand Down
Loading