Add Animate (#130)
This commit is contained in:
parent
283b319edd
commit
8f71b807aa
7 changed files with 110 additions and 45 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
},
|
||||
),
|
||||
),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
Loading…
Reference in a new issue