chore: restrict ui crate visibility and drop unused components
This commit is contained in:
@@ -37,7 +37,7 @@ pub(super) fn avatar_size(size: Size) -> AbsoluteLength {
|
||||
|
||||
/// A deterministic, offline pixel-art avatar derived from a seed.
|
||||
#[derive(IntoElement)]
|
||||
pub struct PixelAvatar {
|
||||
pub(crate) struct PixelAvatar {
|
||||
seed: u64,
|
||||
size: Size,
|
||||
style: StyleRefinement,
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
use gpui::prelude::FluentBuilder as _;
|
||||
use gpui::{
|
||||
div, px, Axis, Div, Hsla, IntoElement, ParentElement, RenderOnce, SharedString, Styled,
|
||||
};
|
||||
use theme::ActiveTheme;
|
||||
|
||||
/// A divider that can be either vertical or horizontal.
|
||||
#[derive(IntoElement)]
|
||||
pub struct Divider {
|
||||
base: Div,
|
||||
label: Option<SharedString>,
|
||||
axis: Axis,
|
||||
color: Option<Hsla>,
|
||||
}
|
||||
|
||||
impl Divider {
|
||||
pub fn vertical() -> Self {
|
||||
Self {
|
||||
base: div().h_full(),
|
||||
axis: Axis::Vertical,
|
||||
label: None,
|
||||
color: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn horizontal() -> Self {
|
||||
Self {
|
||||
base: div().w_full(),
|
||||
axis: Axis::Horizontal,
|
||||
label: None,
|
||||
color: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn label(mut self, label: impl Into<SharedString>) -> Self {
|
||||
self.label = Some(label.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn color(mut self, color: impl Into<Hsla>) -> Self {
|
||||
self.color = Some(color.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Styled for Divider {
|
||||
fn style(&mut self) -> &mut gpui::StyleRefinement {
|
||||
self.base.style()
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for Divider {
|
||||
fn render(self, _window: &mut gpui::Window, cx: &mut gpui::App) -> impl IntoElement {
|
||||
self.base
|
||||
.flex()
|
||||
.flex_shrink_0()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.child(
|
||||
div()
|
||||
.absolute()
|
||||
.rounded_full()
|
||||
.map(|this| match self.axis {
|
||||
Axis::Vertical => this.w(px(1.)).h_full(),
|
||||
Axis::Horizontal => this.h(px(1.)).w_full(),
|
||||
})
|
||||
.bg(self.color.unwrap_or(cx.theme().border_variant)),
|
||||
)
|
||||
.when_some(self.label, |this, label| {
|
||||
this.child(
|
||||
div()
|
||||
.px_2()
|
||||
.py_1()
|
||||
.mx_auto()
|
||||
.text_xs()
|
||||
.bg(cx.theme().background)
|
||||
.child(label),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -31,33 +31,14 @@ pub use panel::*;
|
||||
|
||||
actions!(dock, [ToggleZoom, ClosePanel]);
|
||||
|
||||
pub type TitleBarRenderer = fn(&mut Window, &mut App) -> AnyElement;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TitleBarChrome {
|
||||
trailing: Cell<Option<TitleBarRenderer>>,
|
||||
}
|
||||
|
||||
impl TitleBarChrome {
|
||||
pub fn set_trailing(&self, renderer: TitleBarRenderer) {
|
||||
self.trailing.set(Some(renderer));
|
||||
}
|
||||
|
||||
fn trailing(&self, window: &mut Window, cx: &mut App) -> Option<AnyElement> {
|
||||
self.trailing.get().map(|render| render(window, cx))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dock_area(
|
||||
id: impl Into<SharedString>,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> (Entity<DockArea>, Rc<TitleBarChrome>) {
|
||||
let chrome = Rc::new(TitleBarChrome::default());
|
||||
) -> Entity<DockArea> {
|
||||
let shared = Rc::new(SkinShared {
|
||||
area: RefCell::new(None),
|
||||
resizing: Cell::new(None),
|
||||
chrome: chrome.clone(),
|
||||
});
|
||||
let area = cx.new(|cx| {
|
||||
DockArea::new(id, None, window, cx).with_renderer(Rc::new(DockSkin {
|
||||
@@ -66,7 +47,7 @@ pub fn dock_area(
|
||||
});
|
||||
|
||||
*shared.area.borrow_mut() = Some(area.downgrade());
|
||||
(area, chrome)
|
||||
area
|
||||
}
|
||||
|
||||
pub fn add_panel(
|
||||
@@ -148,33 +129,6 @@ fn find_panel(area: &DockArea, key: &SharedString, cx: &App) -> Option<(PanelId,
|
||||
None
|
||||
}
|
||||
|
||||
pub fn focus_tab_panel(area: &DockArea, window: &mut Window, cx: &mut App) {
|
||||
let Some(tree) = area.layout(DockPlacement::Center) else {
|
||||
return;
|
||||
};
|
||||
let Some(node) = left_top_group(tree.root()) else {
|
||||
return;
|
||||
};
|
||||
let Some(PaneRef::Tabs { panels, active_ix }) = tree.find_node(node).map(PaneNode::kind) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let displayed = match panels.get(active_ix) {
|
||||
Some(panel) if area.panel(*panel).is_some_and(|panel| panel.visible(cx)) => Some(*panel),
|
||||
_ => panels
|
||||
.iter()
|
||||
.copied()
|
||||
.find(|id| area.panel(*id).is_some_and(|panel| panel.visible(cx))),
|
||||
};
|
||||
|
||||
let Some(panel) = displayed.and_then(|id| area.panel(id).cloned()) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let focus_handle = panel.focus_handle(cx);
|
||||
window.focus(&focus_handle, cx);
|
||||
}
|
||||
|
||||
fn left_top_group(node: &PaneNode) -> Option<NodeId> {
|
||||
match node.kind() {
|
||||
PaneRef::Tabs { .. } => Some(node.id()),
|
||||
@@ -200,7 +154,6 @@ fn right_top_group(node: &PaneNode) -> Option<NodeId> {
|
||||
struct SkinShared {
|
||||
area: RefCell<Option<WeakEntity<DockArea>>>,
|
||||
resizing: Cell<Option<DockPlacement>>,
|
||||
chrome: Rc<TitleBarChrome>,
|
||||
}
|
||||
|
||||
impl SkinShared {
|
||||
@@ -487,10 +440,6 @@ impl TabGroupSkin {
|
||||
let needs_traffic_light_padding =
|
||||
cfg!(target_os = "macos") && self.is_leftmost_top_group(group, cx);
|
||||
|
||||
let trailing_chrome = is_title_bar
|
||||
.then(|| self.shared.chrome.trailing(window, cx))
|
||||
.flatten();
|
||||
|
||||
let empty_space = div()
|
||||
.id("tab-bar-empty-space")
|
||||
.h_full()
|
||||
@@ -610,8 +559,7 @@ impl TabGroupSkin {
|
||||
.h_full()
|
||||
.px_0p5()
|
||||
.gap_1()
|
||||
.children(right_button)
|
||||
.children(trailing_chrome),
|
||||
.children(right_button),
|
||||
)
|
||||
});
|
||||
|
||||
|
||||
+2
-15
@@ -1,6 +1,6 @@
|
||||
use gpui::{
|
||||
div, relative, Action, AsKeystroke, FocusHandle, IntoElement, KeyContext, Keystroke,
|
||||
ParentElement as _, RenderOnce, StyleRefinement, Styled, Window,
|
||||
Action, AsKeystroke, FocusHandle, IntoElement, KeyContext, Keystroke, ParentElement as _,
|
||||
RenderOnce, StyleRefinement, Styled, Window, div, relative,
|
||||
};
|
||||
use theme::ActiveTheme;
|
||||
|
||||
@@ -11,7 +11,6 @@ use crate::StyledExt;
|
||||
pub struct Kbd {
|
||||
style: StyleRefinement,
|
||||
stroke: Keystroke,
|
||||
appearance: bool,
|
||||
}
|
||||
|
||||
impl From<Keystroke> for Kbd {
|
||||
@@ -19,7 +18,6 @@ impl From<Keystroke> for Kbd {
|
||||
Self {
|
||||
style: StyleRefinement::default(),
|
||||
stroke,
|
||||
appearance: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,16 +27,9 @@ impl Kbd {
|
||||
Self {
|
||||
style: StyleRefinement::default(),
|
||||
stroke,
|
||||
appearance: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the appearance of the keybinding.
|
||||
pub fn appearance(mut self, appearance: bool) -> Self {
|
||||
self.appearance = appearance;
|
||||
self
|
||||
}
|
||||
|
||||
/// Return the first keybinding for the given action and context.
|
||||
pub fn binding_for_action(
|
||||
action: &dyn Action,
|
||||
@@ -206,10 +197,6 @@ impl Styled for Kbd {
|
||||
|
||||
impl RenderOnce for Kbd {
|
||||
fn render(self, _: &mut gpui::Window, cx: &mut gpui::App) -> impl gpui::IntoElement {
|
||||
if !self.appearance {
|
||||
return Self::format(&self.stroke).into_any_element();
|
||||
}
|
||||
|
||||
div()
|
||||
.border_1()
|
||||
.border_color(cx.theme().border)
|
||||
|
||||
+6
-11
@@ -1,18 +1,13 @@
|
||||
pub use gpui_base::{ElementExt, IndexPath, InteractiveElementExt};
|
||||
pub(crate) use gpui_base::{ElementExt, InteractiveElementExt};
|
||||
pub use icon::*;
|
||||
pub use kbd::*;
|
||||
pub use root::{Root, window_paddings};
|
||||
pub use root::Root;
|
||||
pub use styled::*;
|
||||
pub use title_bar::*;
|
||||
pub use title_bar::{TRAFFIC_LIGHT_PADDING, title_bar_drag_handlers};
|
||||
pub use window_ext::*;
|
||||
|
||||
pub use crate::Disableable;
|
||||
|
||||
pub mod animation;
|
||||
pub mod avatar;
|
||||
pub mod button;
|
||||
pub mod dialog;
|
||||
pub mod divider;
|
||||
pub mod dock;
|
||||
pub mod group_box;
|
||||
pub mod indicator;
|
||||
@@ -23,16 +18,16 @@ pub mod message;
|
||||
pub mod nav;
|
||||
pub mod nav_item;
|
||||
pub mod notification;
|
||||
pub mod popover;
|
||||
pub mod resizable;
|
||||
pub mod scroll;
|
||||
pub mod skeleton;
|
||||
pub mod switch;
|
||||
pub mod tab;
|
||||
pub mod tooltip;
|
||||
|
||||
mod animation;
|
||||
mod icon;
|
||||
mod kbd;
|
||||
mod popover;
|
||||
mod resizable;
|
||||
mod root;
|
||||
mod styled;
|
||||
mod title_bar;
|
||||
|
||||
@@ -34,7 +34,7 @@ impl InlineReplacement {
|
||||
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Highlight {
|
||||
pub(crate) enum Highlight {
|
||||
Code,
|
||||
InlineCode(bool),
|
||||
Replacement,
|
||||
@@ -53,10 +53,10 @@ impl From<HighlightStyle> for Highlight {
|
||||
/// into plain text plus highlight ranges, ready to hand to an `InteractiveText`.
|
||||
#[derive(Default)]
|
||||
pub struct RenderedText {
|
||||
pub text: SharedString,
|
||||
pub highlights: Vec<(Range<usize>, Highlight)>,
|
||||
pub link_ranges: Vec<Range<usize>>,
|
||||
pub link_urls: Arc<[String]>,
|
||||
pub(crate) text: SharedString,
|
||||
pub(crate) highlights: Vec<(Range<usize>, Highlight)>,
|
||||
pub(crate) link_ranges: Vec<Range<usize>>,
|
||||
pub(crate) link_urls: Arc<[String]>,
|
||||
}
|
||||
|
||||
impl RenderedText {
|
||||
|
||||
@@ -510,43 +510,6 @@ impl PopupMenu {
|
||||
self
|
||||
}
|
||||
|
||||
/// Add Menu Item with custom element render.
|
||||
pub fn menu_element<F, E>(self, action: Box<dyn Action>, builder: F) -> Self
|
||||
where
|
||||
F: Fn(&mut Window, &mut App) -> E + 'static,
|
||||
E: IntoElement,
|
||||
{
|
||||
self.menu_element_with_check(false, action, builder)
|
||||
}
|
||||
|
||||
/// Add Menu Item with custom element render with disabled state.
|
||||
pub fn menu_element_with_disabled<F, E>(
|
||||
self,
|
||||
action: Box<dyn Action>,
|
||||
disabled: bool,
|
||||
builder: F,
|
||||
) -> Self
|
||||
where
|
||||
F: Fn(&mut Window, &mut App) -> E + 'static,
|
||||
E: IntoElement,
|
||||
{
|
||||
self.menu_element_with_check_and_disabled(false, action, disabled, builder)
|
||||
}
|
||||
|
||||
/// Add Menu Item with custom element render with icon.
|
||||
pub fn menu_element_with_icon<F, E>(
|
||||
self,
|
||||
icon: impl Into<Icon>,
|
||||
action: Box<dyn Action>,
|
||||
builder: F,
|
||||
) -> Self
|
||||
where
|
||||
F: Fn(&mut Window, &mut App) -> E + 'static,
|
||||
E: IntoElement,
|
||||
{
|
||||
self.menu_element_with_icon_and_disabled(icon, action, false, builder)
|
||||
}
|
||||
|
||||
/// Add Menu Item with custom element render with check state
|
||||
pub fn menu_element_with_check<F, E>(
|
||||
self,
|
||||
@@ -561,27 +524,6 @@ impl PopupMenu {
|
||||
self.menu_element_with_check_and_disabled(checked, action, false, builder)
|
||||
}
|
||||
|
||||
/// Add Menu Item with custom element render with icon and disabled state
|
||||
fn menu_element_with_icon_and_disabled<F, E>(
|
||||
mut self,
|
||||
icon: impl Into<Icon>,
|
||||
action: Box<dyn Action>,
|
||||
disabled: bool,
|
||||
builder: F,
|
||||
) -> Self
|
||||
where
|
||||
F: Fn(&mut Window, &mut App) -> E + 'static,
|
||||
E: IntoElement,
|
||||
{
|
||||
self.menu_items.push(
|
||||
PopupMenuItem::element(builder)
|
||||
.action(action)
|
||||
.icon(icon)
|
||||
.disabled(disabled),
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add Menu Item with custom element render with check state and disabled state
|
||||
fn menu_element_with_check_and_disabled<F, E>(
|
||||
mut self,
|
||||
|
||||
@@ -469,7 +469,7 @@ impl Render for Notification {
|
||||
}
|
||||
|
||||
/// A list of notifications.
|
||||
pub struct NotificationList {
|
||||
pub(crate) struct NotificationList {
|
||||
/// Notifications that will be auto hidden.
|
||||
pub(crate) notifications: ToastManager<NotificationId, Entity<Notification>>,
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ use std::rc::Rc;
|
||||
|
||||
use gpui::prelude::FluentBuilder as _;
|
||||
use gpui::{
|
||||
Anchor, AnyElement, App, Context, Div, ElementId, FocusHandle, InteractiveElement as _,
|
||||
IntoElement, MouseButton, ParentElement, RenderOnce, Stateful, StyleRefinement, Styled, Window,
|
||||
Anchor, AnyElement, App, Context, Div, ElementId, InteractiveElement as _, IntoElement,
|
||||
MouseButton, ParentElement, RenderOnce, Stateful, StyleRefinement, Styled, Window,
|
||||
};
|
||||
use gpui_base::Popover as BasePopover;
|
||||
pub use gpui_base::PopoverState;
|
||||
@@ -16,9 +16,6 @@ pub struct Popover {
|
||||
id: ElementId,
|
||||
style: StyleRefinement,
|
||||
anchor: Anchor,
|
||||
default_open: bool,
|
||||
open: Option<bool>,
|
||||
tracked_focus_handle: Option<FocusHandle>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
trigger: Option<Box<dyn FnOnce(bool, &Window, &App) -> AnyElement + 'static>>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
@@ -35,8 +32,6 @@ pub struct Popover {
|
||||
mouse_button: MouseButton,
|
||||
appearance: bool,
|
||||
overlay_closable: bool,
|
||||
#[allow(clippy::type_complexity)]
|
||||
on_open_change: Option<Rc<dyn Fn(&bool, &mut Window, &mut App)>>,
|
||||
}
|
||||
|
||||
impl Popover {
|
||||
@@ -49,14 +44,10 @@ impl Popover {
|
||||
trigger: None,
|
||||
trigger_style: None,
|
||||
content: None,
|
||||
tracked_focus_handle: None,
|
||||
children: vec![],
|
||||
mouse_button: MouseButton::Left,
|
||||
appearance: true,
|
||||
overlay_closable: true,
|
||||
default_open: false,
|
||||
open: None,
|
||||
on_open_change: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,39 +91,6 @@ impl Popover {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default open state of the popover, default is `false`.
|
||||
///
|
||||
/// This is only used to initialize the open state of the popover.
|
||||
///
|
||||
/// And please note that if you use the `open` method, this value will be ignored.
|
||||
pub fn default_open(mut self, open: bool) -> Self {
|
||||
self.default_open = open;
|
||||
self
|
||||
}
|
||||
|
||||
/// Force set the open state of the popover.
|
||||
///
|
||||
/// If this is set, the popover will be controlled by this value.
|
||||
///
|
||||
/// NOTE: You must be used in conjunction with `on_open_change` to handle state changes.
|
||||
pub fn open(mut self, open: bool) -> Self {
|
||||
self.open = Some(open);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a callback to be called when the open state changes.
|
||||
///
|
||||
/// The first `&bool` parameter is the **new open state**.
|
||||
///
|
||||
/// This is useful when using the `open` method to control the popover state.
|
||||
pub fn on_open_change<F>(mut self, callback: F) -> Self
|
||||
where
|
||||
F: Fn(&bool, &mut Window, &mut App) + 'static,
|
||||
{
|
||||
self.on_open_change = Some(Rc::new(callback));
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the style for the trigger element.
|
||||
pub fn trigger_style(mut self, style: StyleRefinement) -> Self {
|
||||
self.trigger_style = Some(style);
|
||||
@@ -170,15 +128,6 @@ impl Popover {
|
||||
self.appearance = appearance;
|
||||
self
|
||||
}
|
||||
|
||||
/// Bind the focus handle to receive focus when the popover is opened.
|
||||
/// If you not set this, a new focus handle will be created for the popover to
|
||||
///
|
||||
/// If popover is opened, the focus will be moved to the focus handle.
|
||||
pub fn track_focus(mut self, handle: &FocusHandle) -> Self {
|
||||
self.tracked_focus_handle = Some(handle.clone());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl ParentElement for Popover {
|
||||
@@ -224,7 +173,6 @@ impl RenderOnce for Popover {
|
||||
BasePopover::new(self.id)
|
||||
.anchor(anchor)
|
||||
.mouse_button(self.mouse_button)
|
||||
.default_open(self.default_open)
|
||||
.overlay_closable(self.overlay_closable)
|
||||
.content(move |state, window, cx| {
|
||||
Self::render_popover_content(anchor, appearance, window, cx)
|
||||
@@ -235,13 +183,6 @@ impl RenderOnce for Popover {
|
||||
.refine_style(&style)
|
||||
})
|
||||
.when_some(self.trigger, |this, trigger| this.trigger_with(trigger))
|
||||
.when_some(self.open, |this, open| this.open(open))
|
||||
.when_some(self.tracked_focus_handle, |this, handle| {
|
||||
this.track_focus(&handle)
|
||||
})
|
||||
.when_some(self.on_open_change, |this, callback| {
|
||||
this.on_open_change(move |open, window, cx| callback(open, window, cx))
|
||||
})
|
||||
.into_any_element()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,6 @@ use std::rc::Rc;
|
||||
use gpui::prelude::FluentBuilder as _;
|
||||
use gpui::{App, InteractiveElement as _, IntoElement, Pixels, Styled as _, Window, div, px};
|
||||
pub(crate) use gpui_base::resize_handle;
|
||||
pub use gpui_base::{
|
||||
ResizablePanel, ResizablePanelEvent, ResizablePanelGroup, ResizableState, h_resizable,
|
||||
resizable_panel, v_resizable,
|
||||
};
|
||||
use gpui_base::{ResizeHandleContext, ResizeHandleRenderer};
|
||||
use theme::{ActiveTheme as _, AxisExt as _};
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ use crate::notification::{Notification, NotificationList};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub struct ActiveDialog {
|
||||
pub(crate) struct ActiveDialog {
|
||||
focus_handle: FocusHandle,
|
||||
/// The previous focused handle before opening the dialog.
|
||||
previous_focused_handle: Option<WeakFocusHandle>,
|
||||
@@ -193,11 +193,6 @@ impl Root {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Check if there are any active dialogs.
|
||||
pub fn has_active_dialogs(&self) -> bool {
|
||||
!self.active_dialogs.is_empty()
|
||||
}
|
||||
|
||||
/// Push a notification to the notification layer.
|
||||
pub fn push_notification<T>(&mut self, note: T, window: &mut Window, cx: &mut Context<'_, Root>)
|
||||
where
|
||||
@@ -393,7 +388,7 @@ impl Render for Root {
|
||||
}
|
||||
|
||||
/// Get the window paddings.
|
||||
pub fn window_paddings(window: &Window, _cx: &App) -> Edges<Pixels> {
|
||||
pub(crate) fn window_paddings(window: &Window, _cx: &App) -> Edges<Pixels> {
|
||||
match window.window_decorations() {
|
||||
Decorations::Server => Edges::all(px(0.0)),
|
||||
Decorations::Client { tiling } => {
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
use instant::Duration;
|
||||
|
||||
use gpui::{
|
||||
bounce, div, ease_in_out, Animation, AnimationExt, IntoElement, RenderOnce, StyleRefinement,
|
||||
Styled,
|
||||
};
|
||||
use theme::ActiveTheme;
|
||||
|
||||
use crate::StyledExt;
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct Skeleton {
|
||||
style: StyleRefinement,
|
||||
secondary: bool,
|
||||
}
|
||||
|
||||
impl Skeleton {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
style: StyleRefinement::default(),
|
||||
secondary: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn secondary(mut self) -> Self {
|
||||
self.secondary = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Skeleton {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Styled for Skeleton {
|
||||
fn style(&mut self) -> &mut gpui::StyleRefinement {
|
||||
&mut self.style
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for Skeleton {
|
||||
fn render(self, _window: &mut gpui::Window, cx: &mut gpui::App) -> impl IntoElement {
|
||||
let color = if self.secondary {
|
||||
cx.theme().ghost_element_active.opacity(0.5)
|
||||
} else {
|
||||
cx.theme().ghost_element_active
|
||||
};
|
||||
|
||||
div()
|
||||
.w_full()
|
||||
.h_4()
|
||||
.rounded_md()
|
||||
.refine_style(&self.style)
|
||||
.bg(color)
|
||||
.with_animation(
|
||||
"skeleton",
|
||||
Animation::new(Duration::from_secs(3))
|
||||
.repeat()
|
||||
.with_easing(bounce(ease_in_out)),
|
||||
move |this, delta| {
|
||||
let v = 1.0 - delta * 0.5;
|
||||
this.opacity(v)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
+8
-111
@@ -1,5 +1,5 @@
|
||||
use gpui::{App, DefiniteLength, Div, Edges, Pixels, Refineable, StyleRefinement, Styled, div, px};
|
||||
pub use gpui_base::component_traits::{Collapsible, Disableable, Selectable};
|
||||
use gpui::{App, Div, Pixels, Refineable, StyleRefinement, Styled, div, px};
|
||||
pub use gpui_base::component_traits::{Disableable, Selectable};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use theme::ActiveTheme;
|
||||
|
||||
@@ -47,39 +47,9 @@ pub trait StyledExt: Styled + Sized {
|
||||
self.flex().flex_col()
|
||||
}
|
||||
|
||||
/// Apply paddings to the element.
|
||||
fn paddings<L>(self, paddings: impl Into<Edges<L>>) -> Self
|
||||
where
|
||||
L: Into<DefiniteLength> + Clone + Default + std::fmt::Debug + PartialEq,
|
||||
{
|
||||
let paddings = paddings.into();
|
||||
self.pt(paddings.top.into())
|
||||
.pb(paddings.bottom.into())
|
||||
.pl(paddings.left.into())
|
||||
.pr(paddings.right.into())
|
||||
}
|
||||
|
||||
/// Apply margins to the element.
|
||||
fn margins<L>(self, margins: impl Into<Edges<L>>) -> Self
|
||||
where
|
||||
L: Into<DefiniteLength> + Clone + Default + std::fmt::Debug + PartialEq,
|
||||
{
|
||||
let margins = margins.into();
|
||||
self.mt(margins.top.into())
|
||||
.mb(margins.bottom.into())
|
||||
.ml(margins.left.into())
|
||||
.mr(margins.right.into())
|
||||
}
|
||||
|
||||
font_weight!(font_thin, THIN);
|
||||
font_weight!(font_extralight, EXTRA_LIGHT);
|
||||
font_weight!(font_light, LIGHT);
|
||||
font_weight!(font_normal, NORMAL);
|
||||
font_weight!(font_medium, MEDIUM);
|
||||
font_weight!(font_semibold, SEMIBOLD);
|
||||
font_weight!(font_bold, BOLD);
|
||||
font_weight!(font_extrabold, EXTRA_BOLD);
|
||||
font_weight!(font_black, BLACK);
|
||||
|
||||
/// Set as Popover style
|
||||
#[inline]
|
||||
@@ -140,55 +110,13 @@ pub trait Sizable: Sized {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub trait StyleSized<T: Styled> {
|
||||
fn input_font_size(self, size: Size) -> Self;
|
||||
fn input_size(self, size: Size) -> Self;
|
||||
fn input_pl(self, size: Size) -> Self;
|
||||
fn input_pr(self, size: Size) -> Self;
|
||||
pub(crate) trait StyleSized<T: Styled> {
|
||||
fn input_px(self, size: Size) -> Self;
|
||||
fn input_py(self, size: Size) -> Self;
|
||||
fn input_h(self, size: Size) -> Self;
|
||||
fn list_size(self, size: Size) -> Self;
|
||||
fn list_px(self, size: Size) -> Self;
|
||||
fn list_py(self, size: Size) -> Self;
|
||||
/// Apply size with the given `Size`.
|
||||
fn size_with(self, size: Size) -> Self;
|
||||
}
|
||||
|
||||
impl<T: Styled> StyleSized<T> for T {
|
||||
fn input_font_size(self, size: Size) -> Self {
|
||||
match size {
|
||||
Size::XSmall => self.text_xs(),
|
||||
Size::Small => self.text_sm(),
|
||||
Size::Medium => self.text_base(),
|
||||
Size::Large => self.text_lg(),
|
||||
Size::Size(size) => self.text_size(size),
|
||||
}
|
||||
}
|
||||
|
||||
fn input_size(self, size: Size) -> Self {
|
||||
self.input_px(size).input_py(size).input_h(size)
|
||||
}
|
||||
|
||||
fn input_pl(self, size: Size) -> Self {
|
||||
match size {
|
||||
Size::XSmall => self.pl_1(),
|
||||
Size::Medium => self.pl_3(),
|
||||
Size::Large => self.pl_5(),
|
||||
_ => self.pl_2(),
|
||||
}
|
||||
}
|
||||
|
||||
fn input_pr(self, size: Size) -> Self {
|
||||
match size {
|
||||
Size::XSmall => self.pr_1(),
|
||||
Size::Medium => self.pr_3(),
|
||||
Size::Large => self.pr_5(),
|
||||
_ => self.pr_2(),
|
||||
}
|
||||
}
|
||||
|
||||
fn input_px(self, size: Size) -> Self {
|
||||
match size {
|
||||
Size::XSmall => self.px_1(),
|
||||
@@ -209,42 +137,11 @@ impl<T: Styled> StyleSized<T> for T {
|
||||
|
||||
fn input_h(self, size: Size) -> Self {
|
||||
match size {
|
||||
Size::XSmall => self.h_6(),
|
||||
Size::Small => self.h_8(),
|
||||
Size::Medium => self.h_9(),
|
||||
Size::Large => self.h_12(),
|
||||
_ => self.h(px(24.)),
|
||||
}
|
||||
.input_font_size(size)
|
||||
}
|
||||
|
||||
fn list_size(self, size: Size) -> Self {
|
||||
self.list_px(size).list_py(size).input_font_size(size)
|
||||
}
|
||||
|
||||
fn list_px(self, size: Size) -> Self {
|
||||
match size {
|
||||
Size::Small => self.px_2(),
|
||||
_ => self.px_3(),
|
||||
}
|
||||
}
|
||||
|
||||
fn list_py(self, size: Size) -> Self {
|
||||
match size {
|
||||
Size::Large => self.py_2(),
|
||||
Size::Medium => self.py_1(),
|
||||
Size::Small => self.py_0p5(),
|
||||
_ => self.py_1(),
|
||||
}
|
||||
}
|
||||
|
||||
fn size_with(self, size: Size) -> Self {
|
||||
match size {
|
||||
Size::Large => self.size_11(),
|
||||
Size::Medium => self.size_8(),
|
||||
Size::Small => self.size_5(),
|
||||
Size::XSmall => self.size_4(),
|
||||
Size::Size(size) => self.size(size),
|
||||
Size::XSmall => self.h_6().text_xs(),
|
||||
Size::Small => self.h_8().text_sm(),
|
||||
Size::Medium => self.h_9().text_base(),
|
||||
Size::Large => self.h_12().text_lg(),
|
||||
Size::Size(size) => self.h(px(24.)).text_size(size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-158
@@ -2,68 +2,17 @@ use std::rc::Rc;
|
||||
|
||||
use gpui::prelude::FluentBuilder as _;
|
||||
use gpui::{
|
||||
AnyElement, App, ClickEvent, Context, Decorations, Div, Hsla, InteractiveElement, IntoElement,
|
||||
MouseButton, ParentElement, Pixels, Render, RenderOnce, Stateful,
|
||||
StatefulInteractiveElement as _, StyleRefinement, Styled, TitlebarOptions, Window,
|
||||
WindowControlArea, div, px,
|
||||
App, ClickEvent, Context, Div, Hsla, InteractiveElement as _, IntoElement, MouseButton,
|
||||
ParentElement as _, Pixels, Render, RenderOnce, Stateful, StatefulInteractiveElement as _,
|
||||
Styled, Window, WindowControlArea, div, px,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use theme::ActiveTheme;
|
||||
|
||||
use crate::{Icon, IconName, InteractiveElementExt as _, Sizable as _, StyledExt, h_flex};
|
||||
use crate::{Icon, IconName, Sizable as _, h_flex};
|
||||
|
||||
pub const TITLE_BAR_HEIGHT: Pixels = px(34.);
|
||||
pub const TRAFFIC_LIGHT_PADDING: f32 = 80.;
|
||||
|
||||
/// TitleBar used to customize the appearance of the title bar.
|
||||
///
|
||||
/// We can put some elements inside the title bar.
|
||||
#[derive(IntoElement)]
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub struct TitleBar {
|
||||
style: StyleRefinement,
|
||||
children: SmallVec<[AnyElement; 1]>,
|
||||
on_close_window: Option<Rc<Box<dyn Fn(&ClickEvent, &mut Window, &mut App)>>>,
|
||||
}
|
||||
|
||||
impl TitleBar {
|
||||
/// Create a new TitleBar.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
style: StyleRefinement::default(),
|
||||
children: SmallVec::new(),
|
||||
on_close_window: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the default title bar options for compatible with the [`crate::TitleBar`].
|
||||
pub fn title_bar_options() -> TitlebarOptions {
|
||||
TitlebarOptions {
|
||||
title: None,
|
||||
appears_transparent: true,
|
||||
traffic_light_position: Some(gpui::point(px(9.0), px(9.0))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add custom for close window event, default is None, then click X button will call `window.remove_window()`.
|
||||
/// Linux only, this will do nothing on other platforms.
|
||||
pub fn on_close_window(
|
||||
mut self,
|
||||
f: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
if cfg!(target_os = "linux") {
|
||||
self.on_close_window = Some(Rc::new(Box::new(f)));
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TitleBar {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
// The Windows control buttons have a fixed width of 35px.
|
||||
//
|
||||
// We don't need implementation the click event for the control buttons.
|
||||
@@ -287,18 +236,6 @@ impl RenderOnce for WindowControls {
|
||||
}
|
||||
}
|
||||
|
||||
impl Styled for TitleBar {
|
||||
fn style(&mut self) -> &mut gpui::StyleRefinement {
|
||||
&mut self.style
|
||||
}
|
||||
}
|
||||
|
||||
impl ParentElement for TitleBar {
|
||||
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
|
||||
self.children.extend(elements);
|
||||
}
|
||||
}
|
||||
|
||||
struct TitleBarState {
|
||||
should_move: bool,
|
||||
}
|
||||
@@ -308,94 +245,3 @@ impl Render for TitleBarState {
|
||||
div()
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for TitleBar {
|
||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let is_client_decorated = matches!(window.window_decorations(), Decorations::Client { .. });
|
||||
let is_web = cfg!(target_family = "wasm");
|
||||
let is_linux = cfg!(target_os = "linux");
|
||||
let is_macos = cfg!(target_os = "macos");
|
||||
|
||||
let state = window.use_state(cx, |_, _| TitleBarState { should_move: false });
|
||||
|
||||
div().flex_shrink_0().child(
|
||||
div()
|
||||
.id("title-bar")
|
||||
.flex()
|
||||
.flex_row()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.h(TITLE_BAR_HEIGHT)
|
||||
.map(|this| {
|
||||
if window.is_fullscreen() {
|
||||
this.px_2()
|
||||
} else if cx.theme().platform.is_mac() {
|
||||
this.pr_2().pl(px(TRAFFIC_LIGHT_PADDING))
|
||||
} else {
|
||||
this.px_2()
|
||||
}
|
||||
})
|
||||
.bg(cx.theme().title_bar)
|
||||
.refine_style(&self.style)
|
||||
.when(is_linux, |this| {
|
||||
this.on_double_click(|_, window, _| window.zoom_window())
|
||||
})
|
||||
.when(is_macos, |this| {
|
||||
this.on_double_click(|_, window, _| window.titlebar_double_click())
|
||||
})
|
||||
.on_mouse_down_out(window.listener_for(&state, |state, _, _, _| {
|
||||
state.should_move = false;
|
||||
}))
|
||||
.on_mouse_down(
|
||||
MouseButton::Left,
|
||||
window.listener_for(&state, |state, _, _, _| {
|
||||
state.should_move = true;
|
||||
}),
|
||||
)
|
||||
.on_mouse_up(
|
||||
MouseButton::Left,
|
||||
window.listener_for(&state, |state, _, _, _| {
|
||||
state.should_move = false;
|
||||
}),
|
||||
)
|
||||
.on_mouse_move(window.listener_for(&state, |state, _, window, _| {
|
||||
if state.should_move {
|
||||
state.should_move = false;
|
||||
window.start_window_move();
|
||||
}
|
||||
}))
|
||||
.child(
|
||||
h_flex()
|
||||
.id("bar")
|
||||
.h_full()
|
||||
.justify_between()
|
||||
.flex_shrink_0()
|
||||
.flex_1()
|
||||
.when(!is_web, |this| {
|
||||
this.window_control_area(WindowControlArea::Drag)
|
||||
.when(window.is_fullscreen(), |this| this.pl_3())
|
||||
.when(is_linux && is_client_decorated, |this| {
|
||||
this.child(
|
||||
div()
|
||||
.top_0()
|
||||
.left_0()
|
||||
.absolute()
|
||||
.size_full()
|
||||
.h_full()
|
||||
.on_mouse_down(
|
||||
MouseButton::Right,
|
||||
move |ev, window, _| {
|
||||
window.show_window_menu(ev.position)
|
||||
},
|
||||
),
|
||||
)
|
||||
})
|
||||
})
|
||||
.children(self.children),
|
||||
)
|
||||
.child(WindowControls {
|
||||
on_close_window: self.on_close_window,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,6 @@ pub trait WindowExtension: Sized {
|
||||
where
|
||||
F: Fn(Dialog, &mut Window, &mut App) -> Dialog + 'static;
|
||||
|
||||
/// Return true, if there is an active Dialog.
|
||||
fn has_active_dialog(&mut self, cx: &mut App) -> bool;
|
||||
|
||||
/// Closes the last active Dialog.
|
||||
fn close_dialog(&mut self, cx: &mut App);
|
||||
|
||||
@@ -55,11 +52,6 @@ impl WindowExtension for Window {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has_active_dialog(&mut self, cx: &mut App) -> bool {
|
||||
Root::read(self, cx).has_active_dialogs()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn close_dialog(&mut self, cx: &mut App) {
|
||||
Root::update(self, cx, move |root, window, cx| {
|
||||
|
||||
@@ -80,7 +80,7 @@ impl Workspace {
|
||||
let device = DeviceRegistry::global(cx);
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
|
||||
let (dock, _) = dock::dock_area("coop", window, cx);
|
||||
let dock = dock::dock_area("coop", window, cx);
|
||||
let sidebar = cx.new(|cx| Sidebar::new(window, dock.downgrade(), cx));
|
||||
let left_sidebar = sidebar.clone();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user