Add Animate (#130)

This commit is contained in:
Jason Lee 2024-08-09 18:22:06 +08:00 committed by GitHub
parent 283b319edd
commit 8f71b807aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 110 additions and 45 deletions

View file

@ -31,7 +31,7 @@ A UI components for building desktop application by using [GPUI](https://gpui.rs
- [ ] RadioGroup
- [x] Switch
- [x] With Label (Left, Right side)
- [ ] Toggle Animation
- [x] Toggle Animation
- [x] Dropdown
- [x] Tabs
- [x] Tab

View file

@ -2,9 +2,9 @@ use std::{sync::Arc, time::Duration};
use fake::Fake;
use gpui::{
deferred, div, prelude::FluentBuilder as _, px, FocusHandle, FocusableView,
InteractiveElement as _, IntoElement, ParentElement, Render, Styled, Task, Timer, View,
ViewContext, VisualContext as _, WeakView, WindowContext,
deferred, div, prelude::FluentBuilder as _, px, Animation, AnimationExt as _, FocusHandle,
FocusableView, InteractiveElement as _, IntoElement, ParentElement, Render, Styled, Task,
Timer, View, ViewContext, VisualContext as _, WeakView, WindowContext,
};
use ui::{
@ -261,20 +261,33 @@ impl Render for PickerStory {
})
.when(self.open, |this| {
this.child(deferred(
div().absolute().size_full().top_0().left_0().child(
v_flex().flex().flex_col().items_center().child(
v_flex()
.occlude()
.w(px(450.))
.h(px(350.))
.elevation_3(cx)
.child(self.list.clone())
.on_mouse_down_out(cx.listener(|this, _, cx| {
this.open = false;
cx.notify();
})),
div()
.absolute()
.size_full()
.top_0()
.left_0()
.child(
v_flex().flex().flex_col().items_center().child(
v_flex()
.occlude()
.w(px(450.))
.h(px(350.))
.elevation_3(cx)
.child(self.list.clone())
.on_mouse_down_out(cx.listener(|this, _, cx| {
this.open = false;
cx.notify();
})),
),
)
.with_animation(
"slide-down",
Animation::new(Duration::from_secs_f64(0.15)),
move |this, delta| {
let y = px(-10.) + delta * px(10.);
this.top(y).opacity((1.0 * delta + 0.3).min(1.0))
},
),
),
))
})
}

View file

@ -112,7 +112,7 @@ impl Render for SwitchStory {
)
.child(
card(cx).v_flex()
.items_start().child(title("Disabled Switchs")).child(
.items_start().child(title("Small Switchs")).child(
h_flex().items_center()
.gap_6()
.child(Switch::new("switch3").checked(self.switch3).label("Small Size").small().on_click(cx.listener(move |view, checked, cx| {

View file

@ -240,16 +240,18 @@ impl<M: ManagedView> Element for Popover<M> {
.into_any()
} else {
let content_view_mut = element_state.content_view.clone();
let bg_color = cx.theme().popover;
let anchor = view.anchor;
deferred(
anchored.child(
div()
.size_full()
.occlude()
.elevation_2(cx)
.bg(cx.theme().popover)
.bg(bg_color)
.border_1()
.border_color(cx.theme().border)
.map(|this| match view.anchor {
.map(|this| match anchor {
AnchorCorner::TopLeft | AnchorCorner::TopRight => this.top_2(),
AnchorCorner::BottomLeft | AnchorCorner::BottomRight => {
this.bottom_2()

View file

@ -1,11 +1,11 @@
use std::time::Duration;
use gpui::{
bounce, div, ease_in_out, hsla, px, Animation, AnimationExt, Div, IntoElement,
ParentElement as _, RenderOnce, Styled,
bounce, div, ease_in_out, Animation, AnimationExt, Div, IntoElement, ParentElement as _,
RenderOnce, Styled,
};
use crate::theme::{ActiveTheme, Colorize};
use crate::{theme::ActiveTheme, StyledExt};
#[derive(IntoElement)]
pub struct Skeleton {
@ -28,18 +28,15 @@ impl Styled for Skeleton {
impl RenderOnce for Skeleton {
fn render(self, cx: &mut gpui::WindowContext) -> impl IntoElement {
let color = cx.theme().skeleton;
div().child(
self.base.with_animation(
self.base.bg(cx.theme().skeleton).with_animation(
"skeleton",
Animation::new(Duration::from_secs(2))
.repeat()
.with_easing(bounce(ease_in_out)),
move |this, delta| {
let v = 1.0 - delta * 0.5;
let color = color.opacity(v);
this.bg(color)
this.opacity(v)
},
),
)

View file

@ -1,9 +1,9 @@
use crate::{
scroll::{Scrollable, ScrollbarAxis},
theme::ActiveTheme,
theme::{ActiveTheme, Colorize},
};
use gpui::{
hsla, point, px, rems, AnyView, Axis, BoxShadow, Element, FocusHandle, Pixels, Styled,
hsla, point, px, rems, AnyView, Axis, BoxShadow, Element, Fill, FocusHandle, Pixels, Styled,
WindowContext,
};
use smallvec::{smallvec, SmallVec};
@ -174,6 +174,38 @@ pub trait StyledExt: Styled + Sized {
font_weight!(font_bold, BOLD);
font_weight!(font_extrabold, EXTRA_BOLD);
font_weight!(font_black, BLACK);
/// Set the opacity of the element.
fn opacity(mut self, opacity: f32) -> Self {
let bg_color = self.style().background.clone();
let border_color = self.style().border_color;
let box_shadow = self.style().box_shadow.clone();
let this = if let Some(bg) = bg_color {
match bg {
Fill::Color(color) => self.bg(color.opacity(opacity)),
}
} else {
self
};
let this = if let Some(color) = border_color {
this.border_color(color.opacity(opacity))
} else {
this
};
let this = if let Some(mut shadow) = box_shadow {
for shadow in shadow.iter_mut() {
shadow.color = shadow.color.opacity(opacity);
}
this.shadow(shadow)
} else {
this
};
this
}
}
impl<E: Styled> StyledExt for E {}

View file

@ -1,11 +1,14 @@
use std::time::Duration;
use crate::{
stack::h_flex,
theme::{ActiveTheme, Colorize},
Disableable, Sizable, Size,
};
use gpui::{
div, prelude::FluentBuilder as _, Div, InteractiveElement, IntoElement, ParentElement as _,
RenderOnce, SharedString, Stateful, Styled as _, WindowContext,
div, prelude::FluentBuilder as _, px, Animation, AnimationExt as _, Div, ElementId,
InteractiveElement, IntoElement, ParentElement as _, RenderOnce, SharedString, Stateful,
Styled as _, WindowContext,
};
type OnClick = Box<dyn Fn(&bool, &mut WindowContext) + 'static>;
@ -88,6 +91,7 @@ impl RenderOnce for Switch {
fn render(self, cx: &mut gpui::WindowContext) -> impl IntoElement {
let theme = cx.theme();
let group_id = format!("switch_group_{:?}", self.id);
let checked = self.checked;
let (bg, toggle_bg) = match self.checked {
true => (theme.primary, theme.background),
@ -99,6 +103,16 @@ impl RenderOnce for Switch {
false => (bg, toggle_bg),
};
let (bg_width, bg_height) = match self.size {
Size::XSmall | Size::Small => (px(28.), px(16.)),
_ => (px(36.), px(20.)),
};
let bar_width = match self.size {
Size::XSmall | Size::Small => px(12.),
_ => px(16.),
};
let inset = px(2.);
h_flex()
.id(self.id)
.group(group_id)
@ -106,29 +120,36 @@ impl RenderOnce for Switch {
.gap_2()
.when(self.label_side.left(), |this| this.flex_row_reverse())
.child(
// Switch Bar
self.base
.map(|this| match self.size {
Size::XSmall | Size::Small => this.w_8().h_4().rounded_lg(),
_ => this.w_11().h_6().rounded_xl(),
})
.w(bg_width)
.h(bg_height)
.rounded(bg_height / 2.)
.flex()
.items_center()
.border_2()
.border(inset)
.border_color(theme.transparent)
.bg(bg)
.when(!self.disabled, |this| this.cursor_pointer())
.map(|this| match self.checked {
true => this.flex_row_reverse(),
false => this,
})
.child(
// Switch Toggle
div()
.rounded_full()
.bg(toggle_bg)
.map(|this| match self.size {
Size::XSmall | Size::Small => this.w_3().h_3(),
_ => this.w_5().h_5(),
}),
.size(bar_width)
.with_animation(
ElementId::NamedInteger("move".into(), checked as usize),
Animation::new(Duration::from_secs_f64(0.15)),
move |this, delta| {
let max_x = bg_width - bar_width - inset * 2;
let x = if checked {
max_x * delta
} else {
max_x - max_x * delta
};
this.left(x)
},
),
),
)
.when_some(self.label, |this, label| {