diff --git a/assets/icons/editor_atom.svg b/assets/icons/editor_atom.svg
new file mode 100644
index 0000000000..cc5fa83843
--- /dev/null
+++ b/assets/icons/editor_atom.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/editor_cursor.svg b/assets/icons/editor_cursor.svg
new file mode 100644
index 0000000000..338697be8a
--- /dev/null
+++ b/assets/icons/editor_cursor.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/editor_emacs.svg b/assets/icons/editor_emacs.svg
new file mode 100644
index 0000000000..951d7b2be1
--- /dev/null
+++ b/assets/icons/editor_emacs.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/editor_jet_brains.svg b/assets/icons/editor_jet_brains.svg
new file mode 100644
index 0000000000..7d9cf0c65c
--- /dev/null
+++ b/assets/icons/editor_jet_brains.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/editor_sublime.svg b/assets/icons/editor_sublime.svg
new file mode 100644
index 0000000000..95a04f6b54
--- /dev/null
+++ b/assets/icons/editor_sublime.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/editor_vs_code.svg b/assets/icons/editor_vs_code.svg
new file mode 100644
index 0000000000..2a71ad52af
--- /dev/null
+++ b/assets/icons/editor_vs_code.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/shield_check.svg b/assets/icons/shield_check.svg
new file mode 100644
index 0000000000..6e58c31468
--- /dev/null
+++ b/assets/icons/shield_check.svg
@@ -0,0 +1,4 @@
+
diff --git a/crates/icons/src/icons.rs b/crates/icons/src/icons.rs
index 7552060be4..fe68cdd2d6 100644
--- a/crates/icons/src/icons.rs
+++ b/crates/icons/src/icons.rs
@@ -107,6 +107,12 @@ pub enum IconName {
Disconnected,
DocumentText,
Download,
+ EditorAtom,
+ EditorCursor,
+ EditorEmacs,
+ EditorJetBrains,
+ EditorSublime,
+ EditorVsCode,
Ellipsis,
EllipsisVertical,
Envelope,
@@ -229,6 +235,7 @@ pub enum IconName {
Server,
Settings,
SettingsAlt,
+ ShieldCheck,
Shift,
Slash,
SlashSquare,
diff --git a/crates/onboarding/src/ai_setup_page.rs b/crates/onboarding/src/ai_setup_page.rs
index c33dcb9ad1..2f031e7bb8 100644
--- a/crates/onboarding/src/ai_setup_page.rs
+++ b/crates/onboarding/src/ai_setup_page.rs
@@ -43,6 +43,8 @@ fn render_llm_provider_section(
}
fn render_privacy_card(disabled: bool, cx: &mut App) -> impl IntoElement {
+ let privacy_badge = || Badge::new("Privacy").icon(IconName::ShieldCheck);
+
v_flex()
.relative()
.pt_2()
@@ -71,7 +73,7 @@ fn render_privacy_card(disabled: bool, cx: &mut App) -> impl IntoElement {
.size(IconSize::XSmall),
),
)
- .child(Badge::new("PRIVACY").icon(IconName::FileLock)),
+ .child(privacy_badge()),
)
.child(
Label::new("Re-enable it any time in Settings.")
@@ -85,22 +87,17 @@ fn render_privacy_card(disabled: bool, cx: &mut App) -> impl IntoElement {
.justify_between()
.child(Label::new("We don't train models using your data"))
.child(
- h_flex()
- .gap_1()
- .child(Badge::new("Privacy").icon(IconName::FileLock))
- .child(
- Button::new("learn_more", "Learn More")
- .style(ButtonStyle::Outlined)
- .label_size(LabelSize::Small)
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::XSmall)
- .icon_color(Color::Muted)
- .on_click(|_, _, cx| {
- cx.open_url(
- "https://zed.dev/docs/ai/privacy-and-security",
- );
- }),
- ),
+ h_flex().gap_1().child(privacy_badge()).child(
+ Button::new("learn_more", "Learn More")
+ .style(ButtonStyle::Outlined)
+ .label_size(LabelSize::Small)
+ .icon(IconName::ArrowUpRight)
+ .icon_size(IconSize::XSmall)
+ .icon_color(Color::Muted)
+ .on_click(|_, _, cx| {
+ cx.open_url("https://zed.dev/docs/ai/privacy-and-security");
+ }),
+ ),
),
)
.child(
diff --git a/crates/onboarding/src/basics_page.rs b/crates/onboarding/src/basics_page.rs
index aac8241251..327256968a 100644
--- a/crates/onboarding/src/basics_page.rs
+++ b/crates/onboarding/src/basics_page.rs
@@ -48,7 +48,11 @@ fn render_theme_section(window: &mut Window, cx: &mut App) -> impl IntoElement {
let theme_registry = ThemeRegistry::global(cx);
let current_theme_name = theme_selection.theme(appearance);
- let theme_mode = theme_selection.mode();
+ let theme_mode = theme_selection.mode().unwrap_or_default();
+
+ // let theme_mode = theme_selection.mode();
+ // TODO: Clean this up once the "System" button inside the
+ // toggle button group is done
let selected_index = match appearance {
Appearance::Light => 0,
@@ -72,8 +76,28 @@ fn render_theme_section(window: &mut Window, cx: &mut App) -> impl IntoElement {
let is_selected = theme.name == current_theme_name;
let name = theme.name.clone();
let colors = cx.theme().colors();
+
v_flex()
.id(name.clone())
+ .w_full()
+ .items_center()
+ .gap_1()
+ .child(
+ div()
+ .w_full()
+ .border_2()
+ .border_color(colors.border_transparent)
+ .rounded(ThemePreviewTile::CORNER_RADIUS)
+ .map(|this| {
+ if is_selected {
+ this.border_color(colors.border_selected)
+ } else {
+ this.opacity(0.8).hover(|s| s.border_color(colors.border))
+ }
+ })
+ .child(ThemePreviewTile::new(theme.clone(), theme_seed)),
+ )
+ .child(Label::new(name).color(Color::Muted).size(LabelSize::Small))
.on_click({
let theme_name = theme.name.clone();
move |_, _, cx| {
@@ -84,84 +108,45 @@ fn render_theme_section(window: &mut Window, cx: &mut App) -> impl IntoElement {
});
}
})
- .flex_1()
- .child(
- div()
- .border_2()
- .border_color(colors.border_transparent)
- .rounded(ThemePreviewTile::CORNER_RADIUS)
- .hover(|mut style| {
- if !is_selected {
- style.border_color = Some(colors.element_hover);
- }
- style
- })
- .when(is_selected, |this| {
- this.border_color(colors.border_selected)
- })
- .cursor_pointer()
- .child(ThemePreviewTile::new(theme, theme_seed)),
- )
- .child(
- h_flex()
- .justify_center()
- .items_baseline()
- .child(Label::new(name).color(Color::Muted)),
- )
});
return v_flex()
+ .gap_2()
.child(
h_flex().justify_between().child(Label::new("Theme")).child(
- h_flex()
- .gap_2()
- .child(
- ToggleButtonGroup::single_row(
- "theme-selector-onboarding-dark-light",
- [
- ToggleButtonSimple::new("Light", {
- let appearance_state = appearance_state.clone();
- move |_, _, cx| {
- write_appearance_change(
- &appearance_state,
- Appearance::Light,
- cx,
- );
- }
- }),
- ToggleButtonSimple::new("Dark", {
- let appearance_state = appearance_state.clone();
- move |_, _, cx| {
- write_appearance_change(
- &appearance_state,
- Appearance::Dark,
- cx,
- );
- }
- }),
- ],
- )
- .selected_index(selected_index)
- .style(ui::ToggleButtonGroupStyle::Outlined)
- .button_width(rems_from_px(64.)),
- )
- .child(
- ToggleButtonGroup::single_row(
- "theme-selector-onboarding-system",
- [ToggleButtonSimple::new("System", {
- let theme = theme_selection.clone();
- move |_, _, cx| {
- toggle_system_theme_mode(theme.clone(), appearance, cx);
- }
- })],
- )
- .selected_index((theme_mode != Some(ThemeMode::System)) as usize)
- .style(ui::ToggleButtonGroupStyle::Outlined)
- .button_width(rems_from_px(64.)),
- ),
+ ToggleButtonGroup::single_row(
+ "theme-selector-onboarding-dark-light",
+ [
+ ToggleButtonSimple::new("Light", {
+ let appearance_state = appearance_state.clone();
+ move |_, _, cx| {
+ write_appearance_change(&appearance_state, Appearance::Light, cx);
+ }
+ }),
+ ToggleButtonSimple::new("Dark", {
+ let appearance_state = appearance_state.clone();
+ move |_, _, cx| {
+ write_appearance_change(&appearance_state, Appearance::Dark, cx);
+ }
+ }),
+ // TODO: Properly put the System back as a button within this group
+ // Currently, given "System" is not an option in the Appearance enum,
+ // this button doesn't get selected
+ ToggleButtonSimple::new("System", {
+ let theme = theme_selection.clone();
+ move |_, _, cx| {
+ toggle_system_theme_mode(theme.clone(), appearance, cx);
+ }
+ })
+ .selected(theme_mode == ThemeMode::System),
+ ],
+ )
+ .selected_index(selected_index)
+ .style(ui::ToggleButtonGroupStyle::Outlined)
+ .button_width(rems_from_px(64.)),
),
)
- .child(h_flex().justify_between().children(theme_previews));
+ .child(h_flex().gap_4().justify_between().children(theme_previews));
fn write_appearance_change(
appearance_state: &Entity,
@@ -210,7 +195,6 @@ fn render_theme_section(window: &mut Window, cx: &mut App) -> impl IntoElement {
};
ThemeSelection::Dynamic { mode, light, dark }
}
-
ThemeSelection::Dynamic {
mode: _,
light,
@@ -311,30 +295,31 @@ pub(crate) fn render_basics_page(window: &mut Window, cx: &mut App) -> impl Into
ToggleButtonGroup::two_rows(
"multiple_row_test",
[
- ToggleButtonWithIcon::new("VS Code", IconName::AiZed, |_, _, cx| {
+ ToggleButtonWithIcon::new("VS Code", IconName::EditorVsCode, |_, _, cx| {
write_keymap_base(BaseKeymap::VSCode, cx);
}),
- ToggleButtonWithIcon::new("Jetbrains", IconName::AiZed, |_, _, cx| {
+ ToggleButtonWithIcon::new("Jetbrains", IconName::EditorJetBrains, |_, _, cx| {
write_keymap_base(BaseKeymap::JetBrains, cx);
}),
- ToggleButtonWithIcon::new("Sublime Text", IconName::AiZed, |_, _, cx| {
+ ToggleButtonWithIcon::new("Sublime Text", IconName::EditorSublime, |_, _, cx| {
write_keymap_base(BaseKeymap::SublimeText, cx);
}),
],
[
- ToggleButtonWithIcon::new("Atom", IconName::AiZed, |_, _, cx| {
+ ToggleButtonWithIcon::new("Atom", IconName::EditorAtom, |_, _, cx| {
write_keymap_base(BaseKeymap::Atom, cx);
}),
- ToggleButtonWithIcon::new("Emacs", IconName::AiZed, |_, _, cx| {
+ ToggleButtonWithIcon::new("Emacs", IconName::EditorEmacs, |_, _, cx| {
write_keymap_base(BaseKeymap::Emacs, cx);
}),
- ToggleButtonWithIcon::new("Cursor (Beta)", IconName::AiZed, |_, _, cx| {
+ ToggleButtonWithIcon::new("Cursor (Beta)", IconName::EditorCursor, |_, _, cx| {
write_keymap_base(BaseKeymap::Cursor, cx);
}),
],
)
.when_some(base_keymap, |this, base_keymap| this.selected_index(base_keymap))
- .button_width(rems_from_px(230.))
+ .button_width(rems_from_px(216.))
+ .size(ui::ToggleButtonGroupSize::Medium)
.style(ui::ToggleButtonGroupStyle::Outlined)
),
)
diff --git a/crates/onboarding/src/editing_page.rs b/crates/onboarding/src/editing_page.rs
index 759d557805..33d0955d19 100644
--- a/crates/onboarding/src/editing_page.rs
+++ b/crates/onboarding/src/editing_page.rs
@@ -143,7 +143,7 @@ fn render_import_settings_section() -> impl IntoElement {
.gap_1p5()
.px_1()
.child(
- Icon::new(IconName::Sparkle)
+ Icon::new(IconName::EditorVsCode)
.color(Color::Muted)
.size(IconSize::XSmall),
)
@@ -169,7 +169,7 @@ fn render_import_settings_section() -> impl IntoElement {
.gap_1p5()
.px_1()
.child(
- Icon::new(IconName::Sparkle)
+ Icon::new(IconName::EditorCursor)
.color(Color::Muted)
.size(IconSize::XSmall),
)
diff --git a/crates/onboarding/src/onboarding.rs b/crates/onboarding/src/onboarding.rs
index 2ae07b7cd5..21fbeb5d97 100644
--- a/crates/onboarding/src/onboarding.rs
+++ b/crates/onboarding/src/onboarding.rs
@@ -14,8 +14,8 @@ use serde::Deserialize;
use settings::{SettingsStore, VsCodeSettingsSource};
use std::sync::Arc;
use ui::{
- Avatar, FluentBuilder, Headline, KeyBinding, ParentElement as _, StatefulInteractiveElement,
- Vector, VectorName, prelude::*, rems_from_px,
+ Avatar, ButtonLike, FluentBuilder, Headline, KeyBinding, ParentElement as _,
+ StatefulInteractiveElement, Vector, VectorName, prelude::*, rems_from_px,
};
use workspace::{
AppState, Workspace, WorkspaceId,
@@ -344,12 +344,73 @@ impl Onboarding {
.into_element(),
]),
)
- .child(Button::new("skip_all", "Skip All")),
+ .child(
+ ButtonLike::new("skip_all")
+ .child(Label::new("Skip All").ml_1())
+ .on_click(|_, _, cx| {
+ with_active_or_new_workspace(
+ cx,
+ |workspace, window, cx| {
+ let Some((onboarding_id, onboarding_idx)) =
+ workspace
+ .active_pane()
+ .read(cx)
+ .items()
+ .enumerate()
+ .find_map(|(idx, item)| {
+ let _ =
+ item.downcast::()?;
+ Some((item.item_id(), idx))
+ })
+ else {
+ return;
+ };
+
+ workspace.active_pane().update(cx, |pane, cx| {
+ // Get the index here to get around the borrow checker
+ let idx = pane.items().enumerate().find_map(
+ |(idx, item)| {
+ let _ =
+ item.downcast::()?;
+ Some(idx)
+ },
+ );
+
+ if let Some(idx) = idx {
+ pane.activate_item(
+ idx, true, true, window, cx,
+ );
+ } else {
+ let item =
+ Box::new(WelcomePage::new(window, cx));
+ pane.add_item(
+ item,
+ true,
+ true,
+ Some(onboarding_idx),
+ window,
+ cx,
+ );
+ }
+
+ pane.remove_item(
+ onboarding_id,
+ false,
+ false,
+ window,
+ cx,
+ );
+ });
+ },
+ );
+ }),
+ ),
),
)
.child(
if let Some(user) = self.user_store.read(cx).current_user() {
h_flex()
+ .pl_1p5()
.gap_2()
.child(Avatar::new(user.avatar_uri.clone()))
.child(Label::new(user.github_login.clone()))
diff --git a/crates/onboarding/src/theme_preview.rs b/crates/onboarding/src/theme_preview.rs
index 73b540bd40..d51511b7f4 100644
--- a/crates/onboarding/src/theme_preview.rs
+++ b/crates/onboarding/src/theme_preview.rs
@@ -35,7 +35,7 @@ impl RenderOnce for ThemePreviewTile {
let item_skeleton = |w: Length, h: Pixels, bg: Hsla| div().w(w).h(h).rounded_full().bg(bg);
- let skeleton_height = px(4.);
+ let skeleton_height = px(2.);
let sidebar_seeded_width = |seed: f32, index: usize| {
let value = (seed * 1000.0 + index as f32 * 10.0).sin() * 0.5 + 0.5;
@@ -62,12 +62,10 @@ impl RenderOnce for ThemePreviewTile {
.border_color(color.border_transparent)
.bg(color.panel_background)
.child(
- div()
+ v_flex()
.p_2()
- .flex()
- .flex_col()
.size_full()
- .gap(px(4.))
+ .gap_1()
.children(sidebar_skeleton),
);
@@ -143,32 +141,19 @@ impl RenderOnce for ThemePreviewTile {
v_flex()
.size_full()
.p_1()
- .gap(px(6.))
+ .gap_1p5()
.children(lines)
.into_any_element()
};
- let pane = div()
- .h_full()
- .flex_grow()
- .flex()
- .flex_col()
- // .child(
- // div()
- // .w_full()
- // .border_color(color.border)
- // .border_b(px(1.))
- // .h(relative(0.1))
- // .bg(color.tab_bar_background),
- // )
- .child(
- div()
- .size_full()
- .overflow_hidden()
- .bg(color.editor_background)
- .p_2()
- .child(pseudo_code_skeleton(self.theme.clone(), self.seed)),
- );
+ let pane = v_flex().h_full().flex_grow().child(
+ div()
+ .size_full()
+ .overflow_hidden()
+ .bg(color.editor_background)
+ .p_2()
+ .child(pseudo_code_skeleton(self.theme.clone(), self.seed)),
+ );
let content = div().size_full().flex().child(sidebar).child(pane);
diff --git a/crates/onboarding/src/welcome.rs b/crates/onboarding/src/welcome.rs
index 9e524a5e8a..3d2c034367 100644
--- a/crates/onboarding/src/welcome.rs
+++ b/crates/onboarding/src/welcome.rs
@@ -4,11 +4,14 @@ use gpui::{
};
use ui::{ButtonLike, Divider, DividerColor, KeyBinding, Vector, VectorName, prelude::*};
use workspace::{
- NewFile, Open, Workspace, WorkspaceId,
+ NewFile, Open, WorkspaceId,
item::{Item, ItemEvent},
+ with_active_or_new_workspace,
};
use zed_actions::{Extensions, OpenSettings, agent, command_palette};
+use crate::{Onboarding, OpenOnboarding};
+
actions!(
zed,
[
@@ -216,7 +219,64 @@ impl Render for WelcomePage {
div().child(
Button::new("welcome-exit", "Return to Setup")
.full_width()
- .label_size(LabelSize::XSmall),
+ .label_size(LabelSize::XSmall)
+ .on_click(|_, window, cx| {
+ window.dispatch_action(
+ OpenOnboarding.boxed_clone(),
+ cx,
+ );
+
+ with_active_or_new_workspace(cx, |workspace, window, cx| {
+ let Some((welcome_id, welcome_idx)) = workspace
+ .active_pane()
+ .read(cx)
+ .items()
+ .enumerate()
+ .find_map(|(idx, item)| {
+ let _ = item.downcast::()?;
+ Some((item.item_id(), idx))
+ })
+ else {
+ return;
+ };
+
+ workspace.active_pane().update(cx, |pane, cx| {
+ // Get the index here to get around the borrow checker
+ let idx = pane.items().enumerate().find_map(
+ |(idx, item)| {
+ let _ =
+ item.downcast::()?;
+ Some(idx)
+ },
+ );
+
+ if let Some(idx) = idx {
+ pane.activate_item(
+ idx, true, true, window, cx,
+ );
+ } else {
+ let item =
+ Box::new(Onboarding::new(workspace, cx));
+ pane.add_item(
+ item,
+ true,
+ true,
+ Some(welcome_idx),
+ window,
+ cx,
+ );
+ }
+
+ pane.remove_item(
+ welcome_id,
+ false,
+ false,
+ window,
+ cx,
+ );
+ });
+ });
+ }),
),
),
),
@@ -227,7 +287,7 @@ impl Render for WelcomePage {
}
impl WelcomePage {
- pub fn new(window: &mut Window, cx: &mut Context) -> Entity {
+ pub fn new(window: &mut Window, cx: &mut App) -> Entity {
cx.new(|cx| {
let focus_handle = cx.focus_handle();
cx.on_focus(&focus_handle, window, |_, _, cx| cx.notify())
diff --git a/crates/ui/src/components/badge.rs b/crates/ui/src/components/badge.rs
index 9073c88500..2eee084bbb 100644
--- a/crates/ui/src/components/badge.rs
+++ b/crates/ui/src/components/badge.rs
@@ -32,7 +32,7 @@ impl RenderOnce for Badge {
.pl_1()
.pr_2()
.border_1()
- .border_color(cx.theme().colors().border)
+ .border_color(cx.theme().colors().border.opacity(0.6))
.bg(cx.theme().colors().element_background)
.rounded_sm()
.overflow_hidden()
@@ -42,12 +42,7 @@ impl RenderOnce for Badge {
.color(Color::Muted),
)
.child(Divider::vertical().color(DividerColor::Border))
- .child(
- Label::new(self.label.clone())
- .size(LabelSize::XSmall)
- .buffer_font(cx)
- .ml_1(),
- )
+ .child(Label::new(self.label.clone()).size(LabelSize::Small).ml_1())
}
}
diff --git a/crates/ui/src/components/button/button_like.rs b/crates/ui/src/components/button/button_like.rs
index 135ecdfe62..03f7964f35 100644
--- a/crates/ui/src/components/button/button_like.rs
+++ b/crates/ui/src/components/button/button_like.rs
@@ -358,6 +358,7 @@ impl ButtonStyle {
#[derive(Default, PartialEq, Clone, Copy)]
pub enum ButtonSize {
Large,
+ Medium,
#[default]
Default,
Compact,
@@ -368,6 +369,7 @@ impl ButtonSize {
pub fn rems(self) -> Rems {
match self {
ButtonSize::Large => rems_from_px(32.),
+ ButtonSize::Medium => rems_from_px(28.),
ButtonSize::Default => rems_from_px(22.),
ButtonSize::Compact => rems_from_px(18.),
ButtonSize::None => rems_from_px(16.),
@@ -573,7 +575,7 @@ impl RenderOnce for ButtonLike {
})
.gap(DynamicSpacing::Base04.rems(cx))
.map(|this| match self.size {
- ButtonSize::Large => this.px(DynamicSpacing::Base06.rems(cx)),
+ ButtonSize::Large | ButtonSize::Medium => this.px(DynamicSpacing::Base06.rems(cx)),
ButtonSize::Default | ButtonSize::Compact => {
this.px(DynamicSpacing::Base04.rems(cx))
}
diff --git a/crates/ui/src/components/button/toggle_button.rs b/crates/ui/src/components/button/toggle_button.rs
index a621585349..a1e4d65a24 100644
--- a/crates/ui/src/components/button/toggle_button.rs
+++ b/crates/ui/src/components/button/toggle_button.rs
@@ -295,6 +295,7 @@ pub struct ButtonConfiguration {
label: SharedString,
icon: Option,
on_click: Box,
+ selected: bool,
}
mod private {
@@ -308,6 +309,7 @@ pub trait ButtonBuilder: 'static + private::ToggleButtonStyle {
pub struct ToggleButtonSimple {
label: SharedString,
on_click: Box,
+ selected: bool,
}
impl ToggleButtonSimple {
@@ -318,8 +320,14 @@ impl ToggleButtonSimple {
Self {
label: label.into(),
on_click: Box::new(on_click),
+ selected: false,
}
}
+
+ pub fn selected(mut self, selected: bool) -> Self {
+ self.selected = selected;
+ self
+ }
}
impl private::ToggleButtonStyle for ToggleButtonSimple {}
@@ -330,6 +338,7 @@ impl ButtonBuilder for ToggleButtonSimple {
label: self.label,
icon: None,
on_click: self.on_click,
+ selected: self.selected,
}
}
}
@@ -338,6 +347,7 @@ pub struct ToggleButtonWithIcon {
label: SharedString,
icon: IconName,
on_click: Box,
+ selected: bool,
}
impl ToggleButtonWithIcon {
@@ -350,8 +360,14 @@ impl ToggleButtonWithIcon {
label: label.into(),
icon,
on_click: Box::new(on_click),
+ selected: false,
}
}
+
+ pub fn selected(mut self, selected: bool) -> Self {
+ self.selected = selected;
+ self
+ }
}
impl private::ToggleButtonStyle for ToggleButtonWithIcon {}
@@ -362,6 +378,7 @@ impl ButtonBuilder for ToggleButtonWithIcon {
label: self.label,
icon: Some(self.icon),
on_click: self.on_click,
+ selected: self.selected,
}
}
}
@@ -373,6 +390,12 @@ pub enum ToggleButtonGroupStyle {
Outlined,
}
+#[derive(Clone, Copy, PartialEq)]
+pub enum ToggleButtonGroupSize {
+ Default,
+ Medium,
+}
+
#[derive(IntoElement)]
pub struct ToggleButtonGroup
where
@@ -381,6 +404,7 @@ where
group_name: &'static str,
rows: [[T; COLS]; ROWS],
style: ToggleButtonGroupStyle,
+ size: ToggleButtonGroupSize,
button_width: Rems,
selected_index: usize,
}
@@ -391,6 +415,7 @@ impl ToggleButtonGroup {
group_name,
rows: [buttons],
style: ToggleButtonGroupStyle::Transparent,
+ size: ToggleButtonGroupSize::Default,
button_width: rems_from_px(100.),
selected_index: 0,
}
@@ -403,6 +428,7 @@ impl ToggleButtonGroup {
group_name,
rows: [first_row, second_row],
style: ToggleButtonGroupStyle::Transparent,
+ size: ToggleButtonGroupSize::Default,
button_width: rems_from_px(100.),
selected_index: 0,
}
@@ -415,6 +441,11 @@ impl ToggleButtonGroup Self {
+ self.size = size;
+ self
+ }
+
pub fn button_width(mut self, button_width: Rems) -> Self {
self.button_width = button_width;
self
@@ -430,53 +461,56 @@ impl RenderOnce
for ToggleButtonGroup
{
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
- let entries = self.rows.into_iter().enumerate().map(|(row_index, row)| {
- row.into_iter().enumerate().map(move |(col_index, button)| {
- let ButtonConfiguration {
- label,
- icon,
- on_click,
- } = button.into_configuration();
+ let entries =
+ self.rows.into_iter().enumerate().map(|(row_index, row)| {
+ row.into_iter().enumerate().map(move |(col_index, button)| {
+ let ButtonConfiguration {
+ label,
+ icon,
+ on_click,
+ selected,
+ } = button.into_configuration();
- let entry_index = row_index * COLS + col_index;
+ let entry_index = row_index * COLS + col_index;
- ButtonLike::new((self.group_name, entry_index))
- .when(entry_index == self.selected_index, |this| {
- this.toggle_state(true)
- .selected_style(ButtonStyle::Tinted(TintColor::Accent))
- })
- .rounding(None)
- .when(self.style == ToggleButtonGroupStyle::Filled, |button| {
- button.style(ButtonStyle::Filled)
- })
- .child(
- h_flex()
- .min_w(self.button_width)
- .gap_1p5()
- .px_3()
- .py_1()
- .justify_center()
- .when_some(icon, |this, icon| {
- this.child(Icon::new(icon).size(IconSize::XSmall).map(|this| {
- if entry_index == self.selected_index {
- this.color(Color::Accent)
- } else {
- this.color(Color::Muted)
- }
- }))
- })
- .child(
- Label::new(label)
- .size(LabelSize::Small)
- .when(entry_index == self.selected_index, |this| {
- this.color(Color::Accent)
- }),
- ),
- )
- .on_click(on_click)
- .into_any_element()
- })
- });
+ ButtonLike::new((self.group_name, entry_index))
+ .when(entry_index == self.selected_index || selected, |this| {
+ this.toggle_state(true)
+ .selected_style(ButtonStyle::Tinted(TintColor::Accent))
+ })
+ .rounding(None)
+ .when(self.style == ToggleButtonGroupStyle::Filled, |button| {
+ button.style(ButtonStyle::Filled)
+ })
+ .when(self.size == ToggleButtonGroupSize::Medium, |button| {
+ button.size(ButtonSize::Medium)
+ })
+ .child(
+ h_flex()
+ .min_w(self.button_width)
+ .gap_1p5()
+ .px_3()
+ .py_1()
+ .justify_center()
+ .when_some(icon, |this, icon| {
+ this.py_2()
+ .child(Icon::new(icon).size(IconSize::XSmall).map(|this| {
+ if entry_index == self.selected_index || selected {
+ this.color(Color::Accent)
+ } else {
+ this.color(Color::Muted)
+ }
+ }))
+ })
+ .child(Label::new(label).size(LabelSize::Small).when(
+ entry_index == self.selected_index || selected,
+ |this| this.color(Color::Accent),
+ )),
+ )
+ .on_click(on_click)
+ .into_any_element()
+ })
+ });
let border_color = cx.theme().colors().border.opacity(0.6);
let is_outlined_or_filled = self.style == ToggleButtonGroupStyle::Outlined