T11b loading: progress bars and rings that glide, loading overlay, lazy load, suspense and async view, refresh and typing indicators, upload list; draw-time notifies ask for a frame

This commit is contained in:
ZacharyZhang-NY committed 2026-09-25 17:27:21 -04:00
1 parent d4066661d5
commit ce31c7fb06
38 files changed
+1646 -91

No files matched your search

+8 -49
View File
@@ -1,12 +1,12 @@
use gpui::{
Animation, AnimationExt, AnyElement, App, AppContext, Bounds, IntoElement, ParentElement,
RenderOnce, SharedString, Styled, Window, WindowBounds, WindowHandle, WindowOptions, div,
prelude::*, relative,
Animation, AnimationExt, App, AppContext, Bounds, IntoElement, ParentElement, RenderOnce,
SharedString, Styled, Window, WindowBounds, WindowHandle, WindowOptions, div, prelude::*,
relative,
};
use super::{Hosted, open_hosted};
use crate::{
motion,
motion::{self, ProgressBar},
primitives::{Icon, IconName},
theme::{ActiveTheme, ControlSize, IconSize, Radius, TextSize},
typography::{Caption, CopyableText, ExternalLink, Paragraph, Title},
@@ -32,50 +32,6 @@ fn mark(name: &SharedString, icon: Option<IconName>, cx: &App) -> impl IntoEleme
})
}
/// A thin track: `Some` fills to the value, `None` sweeps.
pub(super) fn progress_track(value: Option<f32>, cx: &App) -> AnyElement {
let theme = cx.theme();
let colors = &theme.colors;
let fill = div()
.absolute()
.top_0()
.h_full()
.rounded_full()
.bg(colors.fg);
let track = div()
.relative()
.w_full()
.h(theme.progress_thickness())
.rounded_full()
.overflow_hidden()
.bg(colors.border);
match value {
Some(value) => {
assert!(
(0.0..=1.0).contains(&value),
"progress {value} is not 0..=1"
);
track
.child(fill.left_0().w(relative(value)))
.into_any_element()
}
None if theme.reduced_motion => track
.child(fill.left(relative(0.35)).w(relative(0.3)))
.into_any_element(),
None => track
.child(
fill.w(relative(0.3)).with_animation(
"progress-sweep",
Animation::new(motion::duration(motion::SLOW, cx) * 4)
.repeat()
.with_easing(motion::ease_in_out_cubic),
|bar, t| bar.left(relative(-0.3 + 1.3 * t)),
),
)
.into_any_element(),
}
}
/// Name, version, credits: the About window's content.
#[derive(IntoElement, Clone)]
pub struct AboutDialog {
@@ -243,7 +199,10 @@ impl RenderOnce for SplashScreen {
let theme = cx.theme();
let colors = &theme.colors;
let enter = motion::duration(motion::SLOW, cx);
let track = progress_track(self.progress, cx);
let track = match self.progress {
Some(value) => ProgressBar::new("splash-progress", value).into_any_element(),
None => ProgressBar::indeterminate("splash-progress").into_any_element(),
};
div()
.size_full()
.flex()
+8 -7
View File
@@ -5,10 +5,11 @@ use gpui::{
Window, WindowHandle, div, prelude::*,
};
use super::{Hosted, dialogs::progress_track, open_hosted};
use super::{Hosted, open_hosted};
use crate::{
buttons::{Button, ButtonVariant, IconButton},
layout::ScrollArea,
motion::ProgressBar,
primitives::{Icon, IconName},
theme::{ActiveTheme, ControlSize, IconSize, Radius, TextSize},
typography::{Caption, Label, Title},
@@ -33,9 +34,11 @@ struct Actions {
later: Option<Action>,
}
fn progress_line(state: UpdateState, cx: &App) -> Option<AnyElement> {
fn progress_line(state: UpdateState) -> Option<AnyElement> {
match state {
UpdateState::Downloading(value) => Some(progress_track(Some(value), cx)),
UpdateState::Downloading(value) => {
Some(ProgressBar::new("update-progress", value).into_any_element())
}
_ => None,
}
}
@@ -159,7 +162,7 @@ impl RenderOnce for UpdateBanner {
.on_click(move |_, window, cx| dismiss(window, cx)),
)
})
.when_some(progress_line(self.state, cx), |banner, line| {
.when_some(progress_line(self.state), |banner, line| {
banner.child(div().absolute().left_0().right_0().bottom_0().child(line))
})
}
@@ -258,9 +261,7 @@ impl RenderOnce for UpdateDialog {
),
),
)
.when_some(progress_line(self.state, cx), |dialog, line| {
dialog.child(line)
})
.when_some(progress_line(self.state), |dialog, line| dialog.child(line))
.child(div().flex().justify_end().gap_2().children(buttons(
self.state,
&self.actions,