Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T05:34:14.686Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

split_button.rs

107 lines · 3.2 KB · rust
1use gpui::{
2    AnyElement, App, BoxShadow, ParentElement, RenderOnce, Styled, Window, div, hsla, prelude::*,
3    px,
4};
5
6use theme::ActiveTheme;
7
8use crate::{Divider, ElevationIndex, prelude::*};
9
10use super::ButtonLike;
11
12#[derive(Clone, Copy, PartialEq)]
13pub enum SplitButtonStyle {
14    Filled,
15    Outlined,
16    Transparent,
17}
18
19pub enum SplitButtonKind {
20    ButtonLike(ButtonLike),
21    IconButton(IconButton),
22}
23
24impl From<IconButton> for SplitButtonKind {
25    fn from(icon_button: IconButton) -> Self {
26        Self::IconButton(icon_button)
27    }
28}
29
30impl From<ButtonLike> for SplitButtonKind {
31    fn from(button_like: ButtonLike) -> Self {
32        Self::ButtonLike(button_like)
33    }
34}
35
36/// /// A button with two parts: a primary action on the left and a secondary action on the right.
37///
38/// The left side is a [`ButtonLike`] with the main action, while the right side can contain
39/// any element (typically a dropdown trigger or similar).
40///
41/// The two sections are visually separated by a divider, but presented as a unified control.
42#[derive(IntoElement)]
43pub struct SplitButton {
44    left: SplitButtonKind,
45    right: AnyElement,
46    style: SplitButtonStyle,
47}
48
49impl SplitButton {
50    pub fn new(left: impl Into<SplitButtonKind>, right: AnyElement) -> Self {
51        Self {
52            left: left.into(),
53            right,
54            style: SplitButtonStyle::Filled,
55        }
56    }
57
58    pub fn style(mut self, style: SplitButtonStyle) -> Self {
59        self.style = style;
60        self
61    }
62}
63
64impl RenderOnce for SplitButton {
65    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
66        let is_filled_or_outlined = matches!(
67            self.style,
68            SplitButtonStyle::Filled | SplitButtonStyle::Outlined
69        );
70
71        let outline = BoxShadow::new(px(0.), px(0.), cx.theme().colors().border.opacity(0.8))
72            .spread_radius(px(1.))
73            .inset();
74
75        h_flex()
76            .when(is_filled_or_outlined, |this| this.relative().rounded_sm())
77            .when(self.style == SplitButtonStyle::Transparent, |this| {
78                this.gap_px()
79            })
80            .child(div().flex_grow_1().child(match self.left {
81                SplitButtonKind::ButtonLike(button) => button.into_any_element(),
82                SplitButtonKind::IconButton(icon) => icon.into_any_element(),
83            }))
84            .child(Divider::vertical().when(is_filled_or_outlined, |s| {
85                s.h_full().color(crate::DividerColor::Border)
86            }))
87            .child(self.right)
88            .when(is_filled_or_outlined, |this| {
89                this.child(
90                    div()
91                        .absolute()
92                        .inset_0()
93                        .rounded_sm()
94                        .shadow(vec![outline]),
95                )
96            })
97            .when(self.style == SplitButtonStyle::Filled, |this| {
98                this.bg(ElevationIndex::Surface.on_elevation_bg(cx))
99                    .shadow(vec![BoxShadow::new(
100                        px(0.),
101                        px(1.),
102                        hsla(0.0, 0.0, 0.0, 0.16),
103                    )])
104            })
105    }
106}
107
Served at tenant.openagents/omega Member data and write actions are omitted.