onboarding: Refine page and component designs (#35387)
Includes adding new variants to the Dropdown and Numeric Stepper components. Release Notes: - N/A
This commit is contained in:
parent
b1a7993544
commit
5488398986
5 changed files with 563 additions and 327 deletions
103
crates/onboarding/src/basics_page.rs
Normal file
103
crates/onboarding/src/basics_page.rs
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
use fs::Fs;
|
||||||
|
use gpui::{App, IntoElement, Window};
|
||||||
|
use settings::{Settings, update_settings_file};
|
||||||
|
use theme::{ThemeMode, ThemeSettings};
|
||||||
|
use ui::{SwitchField, ToggleButtonGroup, ToggleButtonSimple, ToggleButtonWithIcon, prelude::*};
|
||||||
|
|
||||||
|
fn read_theme_selection(cx: &App) -> ThemeMode {
|
||||||
|
let settings = ThemeSettings::get_global(cx);
|
||||||
|
settings
|
||||||
|
.theme_selection
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|selection| selection.mode())
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_theme_selection(theme_mode: ThemeMode, cx: &App) {
|
||||||
|
let fs = <dyn Fs>::global(cx);
|
||||||
|
|
||||||
|
update_settings_file::<ThemeSettings>(fs, cx, move |settings, _| {
|
||||||
|
settings.set_mode(theme_mode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_theme_section(cx: &mut App) -> impl IntoElement {
|
||||||
|
let theme_mode = read_theme_selection(cx);
|
||||||
|
|
||||||
|
h_flex().justify_between().child(Label::new("Theme")).child(
|
||||||
|
ToggleButtonGroup::single_row(
|
||||||
|
"theme-selector-onboarding",
|
||||||
|
[
|
||||||
|
ToggleButtonSimple::new("Light", |_, _, cx| {
|
||||||
|
write_theme_selection(ThemeMode::Light, cx)
|
||||||
|
}),
|
||||||
|
ToggleButtonSimple::new("Dark", |_, _, cx| {
|
||||||
|
write_theme_selection(ThemeMode::Dark, cx)
|
||||||
|
}),
|
||||||
|
ToggleButtonSimple::new("System", |_, _, cx| {
|
||||||
|
write_theme_selection(ThemeMode::System, cx)
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.selected_index(match theme_mode {
|
||||||
|
ThemeMode::Light => 0,
|
||||||
|
ThemeMode::Dark => 1,
|
||||||
|
ThemeMode::System => 2,
|
||||||
|
})
|
||||||
|
.style(ui::ToggleButtonGroupStyle::Outlined)
|
||||||
|
.button_width(rems_from_px(64.)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_telemetry_section() -> impl IntoElement {
|
||||||
|
v_flex()
|
||||||
|
.gap_3()
|
||||||
|
.child(Label::new("Telemetry").size(LabelSize::Large))
|
||||||
|
.child(SwitchField::new(
|
||||||
|
"vim_mode",
|
||||||
|
"Help Improve Zed",
|
||||||
|
"Sending anonymous usage data helps us build the right features and create the best experience.",
|
||||||
|
ui::ToggleState::Selected,
|
||||||
|
|_, _, _| {},
|
||||||
|
))
|
||||||
|
.child(SwitchField::new(
|
||||||
|
"vim_mode",
|
||||||
|
"Help Fix Zed",
|
||||||
|
"Send crash reports so we can fix critical issues fast.",
|
||||||
|
ui::ToggleState::Selected,
|
||||||
|
|_, _, _| {},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn render_basics_page(_: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.child(render_theme_section(cx))
|
||||||
|
.child(
|
||||||
|
v_flex().gap_2().child(Label::new("Base Keymap")).child(
|
||||||
|
ToggleButtonGroup::two_rows(
|
||||||
|
"multiple_row_test",
|
||||||
|
[
|
||||||
|
ToggleButtonWithIcon::new("VS Code", IconName::AiZed, |_, _, _| {}),
|
||||||
|
ToggleButtonWithIcon::new("Jetbrains", IconName::AiZed, |_, _, _| {}),
|
||||||
|
ToggleButtonWithIcon::new("Sublime Text", IconName::AiZed, |_, _, _| {}),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
ToggleButtonWithIcon::new("Atom", IconName::AiZed, |_, _, _| {}),
|
||||||
|
ToggleButtonWithIcon::new("Emacs", IconName::AiZed, |_, _, _| {}),
|
||||||
|
ToggleButtonWithIcon::new("Cursor (Beta)", IconName::AiZed, |_, _, _| {}),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.button_width(rems_from_px(230.))
|
||||||
|
.style(ui::ToggleButtonGroupStyle::Outlined)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(v_flex().justify_center().child(div().h_0().child("hack").invisible()).child(SwitchField::new(
|
||||||
|
"vim_mode",
|
||||||
|
"Vim Mode",
|
||||||
|
"Coming from Neovim? Zed's first-class implementation of Vim Mode has got your back.",
|
||||||
|
ui::ToggleState::Selected,
|
||||||
|
|_, _, _| {},
|
||||||
|
)))
|
||||||
|
.child(render_telemetry_section())
|
||||||
|
}
|
|
@ -6,10 +6,8 @@ use project::project_settings::ProjectSettings;
|
||||||
use settings::{Settings as _, update_settings_file};
|
use settings::{Settings as _, update_settings_file};
|
||||||
use theme::{FontFamilyCache, FontFamilyName, ThemeSettings};
|
use theme::{FontFamilyCache, FontFamilyName, ThemeSettings};
|
||||||
use ui::{
|
use ui::{
|
||||||
Clickable, ContextMenu, DropdownMenu, IconButton, Label, LabelCommon, LabelSize,
|
ButtonLike, ContextMenu, DropdownMenu, NumericStepper, SwitchField, ToggleButtonGroup,
|
||||||
NumericStepper, ParentElement, SharedString, Styled, SwitchColor, SwitchField,
|
ToggleButtonGroupStyle, ToggleButtonSimple, ToggleState, prelude::*,
|
||||||
ToggleButtonGroup, ToggleButtonGroupStyle, ToggleButtonSimple, ToggleState, div, h_flex, px,
|
|
||||||
v_flex,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{ImportCursorSettings, ImportVsCodeSettings};
|
use crate::{ImportCursorSettings, ImportVsCodeSettings};
|
||||||
|
@ -118,153 +116,212 @@ fn write_buffer_font_family(font_family: SharedString, cx: &mut App) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn render_editing_page(window: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render_import_settings_section() -> impl IntoElement {
|
||||||
|
v_flex()
|
||||||
|
.gap_4()
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.child(Label::new("Import Settings").size(LabelSize::Large))
|
||||||
|
.child(
|
||||||
|
Label::new("Automatically pull your settings from other editors.")
|
||||||
|
.color(Color::Muted),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.w_full()
|
||||||
|
.gap_4()
|
||||||
|
.child(
|
||||||
|
h_flex().w_full().child(
|
||||||
|
ButtonLike::new("import_vs_code")
|
||||||
|
.full_width()
|
||||||
|
.style(ButtonStyle::Outlined)
|
||||||
|
.size(ButtonSize::Large)
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.w_full()
|
||||||
|
.gap_1p5()
|
||||||
|
.px_1()
|
||||||
|
.child(
|
||||||
|
Icon::new(IconName::Sparkle)
|
||||||
|
.color(Color::Muted)
|
||||||
|
.size(IconSize::XSmall),
|
||||||
|
)
|
||||||
|
.child(Label::new("VS Code")),
|
||||||
|
)
|
||||||
|
.on_click(|_, window, cx| {
|
||||||
|
window.dispatch_action(
|
||||||
|
ImportVsCodeSettings::default().boxed_clone(),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
h_flex().w_full().child(
|
||||||
|
ButtonLike::new("import_cursor")
|
||||||
|
.full_width()
|
||||||
|
.style(ButtonStyle::Outlined)
|
||||||
|
.size(ButtonSize::Large)
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.w_full()
|
||||||
|
.gap_1p5()
|
||||||
|
.px_1()
|
||||||
|
.child(
|
||||||
|
Icon::new(IconName::Sparkle)
|
||||||
|
.color(Color::Muted)
|
||||||
|
.size(IconSize::XSmall),
|
||||||
|
)
|
||||||
|
.child(Label::new("Cursor")),
|
||||||
|
)
|
||||||
|
.on_click(|_, window, cx| {
|
||||||
|
window.dispatch_action(
|
||||||
|
ImportCursorSettings::default().boxed_clone(),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_font_customization_section(window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
let theme_settings = ThemeSettings::get_global(cx);
|
let theme_settings = ThemeSettings::get_global(cx);
|
||||||
let ui_font_size = theme_settings.ui_font_size(cx);
|
let ui_font_size = theme_settings.ui_font_size(cx);
|
||||||
let font_family = theme_settings.buffer_font.family.clone();
|
let font_family = theme_settings.buffer_font.family.clone();
|
||||||
let buffer_font_size = theme_settings.buffer_font_size(cx);
|
let buffer_font_size = theme_settings.buffer_font_size(cx);
|
||||||
|
|
||||||
v_flex()
|
h_flex()
|
||||||
|
.w_full()
|
||||||
.gap_4()
|
.gap_4()
|
||||||
.child(Label::new("Import Settings").size(LabelSize::Large))
|
|
||||||
.child(
|
.child(
|
||||||
Label::new("Automatically pull your settings from other editors.")
|
v_flex()
|
||||||
.size(LabelSize::Small),
|
.w_full()
|
||||||
)
|
.gap_1()
|
||||||
.child(
|
.child(Label::new("UI Font"))
|
||||||
h_flex()
|
|
||||||
.child(
|
.child(
|
||||||
IconButton::new("import-vs-code-settings", ui::IconName::Code).on_click(
|
h_flex()
|
||||||
|_, window, cx| {
|
.w_full()
|
||||||
window
|
|
||||||
.dispatch_action(ImportVsCodeSettings::default().boxed_clone(), cx)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
IconButton::new("import-cursor-settings", ui::IconName::CursorIBeam).on_click(
|
|
||||||
|_, window, cx| {
|
|
||||||
window
|
|
||||||
.dispatch_action(ImportCursorSettings::default().boxed_clone(), cx)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.child(Label::new("Popular Settings").size(LabelSize::Large))
|
|
||||||
.child(
|
|
||||||
h_flex()
|
|
||||||
.gap_4()
|
|
||||||
.justify_between()
|
|
||||||
.child(
|
|
||||||
v_flex()
|
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.gap_1()
|
.gap_2()
|
||||||
.child(Label::new("UI Font"))
|
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
DropdownMenu::new(
|
||||||
.justify_between()
|
"ui-font-family",
|
||||||
.gap_2()
|
theme_settings.ui_font.family.clone(),
|
||||||
.child(div().min_w(px(120.)).child(DropdownMenu::new(
|
ContextMenu::build(window, cx, |mut menu, _, cx| {
|
||||||
"ui-font-family",
|
let font_family_cache = FontFamilyCache::global(cx);
|
||||||
theme_settings.ui_font.family.clone(),
|
|
||||||
ContextMenu::build(window, cx, |mut menu, _, cx| {
|
|
||||||
let font_family_cache = FontFamilyCache::global(cx);
|
|
||||||
|
|
||||||
for font_name in font_family_cache.list_font_families(cx) {
|
for font_name in font_family_cache.list_font_families(cx) {
|
||||||
menu = menu.custom_entry(
|
menu = menu.custom_entry(
|
||||||
{
|
{
|
||||||
let font_name = font_name.clone();
|
let font_name = font_name.clone();
|
||||||
move |_window, _cx| {
|
move |_window, _cx| {
|
||||||
Label::new(font_name.clone())
|
Label::new(font_name.clone()).into_any_element()
|
||||||
.into_any_element()
|
}
|
||||||
}
|
},
|
||||||
},
|
{
|
||||||
{
|
let font_name = font_name.clone();
|
||||||
let font_name = font_name.clone();
|
move |_window, cx| {
|
||||||
move |_window, cx| {
|
write_ui_font_family(font_name.clone(), cx);
|
||||||
write_ui_font_family(font_name.clone(), cx);
|
}
|
||||||
}
|
},
|
||||||
},
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
menu
|
menu
|
||||||
}),
|
}),
|
||||||
)))
|
)
|
||||||
.child(
|
.style(ui::DropdownStyle::Outlined)
|
||||||
NumericStepper::new(
|
.full_width(true),
|
||||||
"ui-font-size",
|
)
|
||||||
ui_font_size.to_string(),
|
|
||||||
move |_, _, cx| {
|
|
||||||
write_ui_font_size(ui_font_size - px(1.), cx);
|
|
||||||
},
|
|
||||||
move |_, _, cx| {
|
|
||||||
write_ui_font_size(ui_font_size + px(1.), cx);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.border(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
v_flex()
|
|
||||||
.justify_between()
|
|
||||||
.gap_1()
|
|
||||||
.child(Label::new("Editor Font"))
|
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
NumericStepper::new(
|
||||||
.justify_between()
|
"ui-font-size",
|
||||||
.gap_2()
|
ui_font_size.to_string(),
|
||||||
.child(DropdownMenu::new(
|
move |_, _, cx| {
|
||||||
"buffer-font-family",
|
write_ui_font_size(ui_font_size - px(1.), cx);
|
||||||
font_family,
|
},
|
||||||
ContextMenu::build(window, cx, |mut menu, _, cx| {
|
move |_, _, cx| {
|
||||||
let font_family_cache = FontFamilyCache::global(cx);
|
write_ui_font_size(ui_font_size + px(1.), cx);
|
||||||
|
},
|
||||||
for font_name in font_family_cache.list_font_families(cx) {
|
)
|
||||||
menu = menu.custom_entry(
|
.style(ui::NumericStepperStyle::Outlined),
|
||||||
{
|
|
||||||
let font_name = font_name.clone();
|
|
||||||
move |_window, _cx| {
|
|
||||||
Label::new(font_name.clone())
|
|
||||||
.into_any_element()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
let font_name = font_name.clone();
|
|
||||||
move |_window, cx| {
|
|
||||||
write_buffer_font_family(
|
|
||||||
font_name.clone(),
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
menu
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
.child(
|
|
||||||
NumericStepper::new(
|
|
||||||
"buffer-font-size",
|
|
||||||
buffer_font_size.to_string(),
|
|
||||||
move |_, _, cx| {
|
|
||||||
write_buffer_font_size(buffer_font_size - px(1.), cx);
|
|
||||||
},
|
|
||||||
move |_, _, cx| {
|
|
||||||
write_buffer_font_size(buffer_font_size + px(1.), cx);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.border(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.w_full()
|
||||||
|
.gap_1()
|
||||||
|
.child(Label::new("Editor Font"))
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.w_full()
|
||||||
|
.justify_between()
|
||||||
|
.gap_2()
|
||||||
|
.child(
|
||||||
|
DropdownMenu::new(
|
||||||
|
"buffer-font-family",
|
||||||
|
font_family,
|
||||||
|
ContextMenu::build(window, cx, |mut menu, _, cx| {
|
||||||
|
let font_family_cache = FontFamilyCache::global(cx);
|
||||||
|
|
||||||
|
for font_name in font_family_cache.list_font_families(cx) {
|
||||||
|
menu = menu.custom_entry(
|
||||||
|
{
|
||||||
|
let font_name = font_name.clone();
|
||||||
|
move |_window, _cx| {
|
||||||
|
Label::new(font_name.clone()).into_any_element()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
let font_name = font_name.clone();
|
||||||
|
move |_window, cx| {
|
||||||
|
write_buffer_font_family(font_name.clone(), cx);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
menu
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.style(ui::DropdownStyle::Outlined)
|
||||||
|
.full_width(true),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
NumericStepper::new(
|
||||||
|
"buffer-font-size",
|
||||||
|
buffer_font_size.to_string(),
|
||||||
|
move |_, _, cx| {
|
||||||
|
write_buffer_font_size(buffer_font_size - px(1.), cx);
|
||||||
|
},
|
||||||
|
move |_, _, cx| {
|
||||||
|
write_buffer_font_size(buffer_font_size + px(1.), cx);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.style(ui::NumericStepperStyle::Outlined),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_popular_settings_section(window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
|
v_flex()
|
||||||
|
.gap_5()
|
||||||
|
.child(Label::new("Popular Settings").size(LabelSize::Large).mt_8())
|
||||||
|
.child(render_font_customization_section(window, cx))
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
|
.items_start()
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.child(Label::new("Mini Map"))
|
.child(
|
||||||
|
v_flex().child(Label::new("Mini Map")).child(
|
||||||
|
Label::new("See a high-level overview of your source code.")
|
||||||
|
.color(Color::Muted),
|
||||||
|
),
|
||||||
|
)
|
||||||
.child(
|
.child(
|
||||||
ToggleButtonGroup::single_row(
|
ToggleButtonGroup::single_row(
|
||||||
"onboarding-show-mini-map",
|
"onboarding-show-mini-map",
|
||||||
|
@ -289,36 +346,37 @@ pub(crate) fn render_editing_page(window: &mut Window, cx: &mut App) -> impl Int
|
||||||
.button_width(ui::rems_from_px(64.)),
|
.button_width(ui::rems_from_px(64.)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(SwitchField::new(
|
||||||
SwitchField::new(
|
"onboarding-enable-inlay-hints",
|
||||||
"onboarding-enable-inlay-hints",
|
"Inlay Hints",
|
||||||
"Inlay Hints",
|
"See parameter names for function and method calls inline.",
|
||||||
"See parameter names for function and method calls inline.",
|
if read_inlay_hints(cx) {
|
||||||
if read_inlay_hints(cx) {
|
ui::ToggleState::Selected
|
||||||
ui::ToggleState::Selected
|
} else {
|
||||||
} else {
|
ui::ToggleState::Unselected
|
||||||
ui::ToggleState::Unselected
|
},
|
||||||
},
|
|toggle_state, _, cx| {
|
||||||
|toggle_state, _, cx| {
|
write_inlay_hints(toggle_state == &ToggleState::Selected, cx);
|
||||||
write_inlay_hints(toggle_state == &ToggleState::Selected, cx);
|
},
|
||||||
},
|
))
|
||||||
)
|
.child(SwitchField::new(
|
||||||
.color(SwitchColor::Accent),
|
"onboarding-git-blame-switch",
|
||||||
)
|
"Git Blame",
|
||||||
.child(
|
"See who committed each line on a given file.",
|
||||||
SwitchField::new(
|
if read_git_blame(cx) {
|
||||||
"onboarding-git-blame-switch",
|
ui::ToggleState::Selected
|
||||||
"Git Blame",
|
} else {
|
||||||
"See who committed each line on a given file.",
|
ui::ToggleState::Unselected
|
||||||
if read_git_blame(cx) {
|
},
|
||||||
ui::ToggleState::Selected
|
|toggle_state, _, cx| {
|
||||||
} else {
|
set_git_blame(toggle_state == &ToggleState::Selected, cx);
|
||||||
ui::ToggleState::Unselected
|
},
|
||||||
},
|
))
|
||||||
|toggle_state, _, cx| {
|
}
|
||||||
set_git_blame(toggle_state == &ToggleState::Selected, cx);
|
|
||||||
},
|
pub(crate) fn render_editing_page(window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
)
|
v_flex()
|
||||||
.color(SwitchColor::Accent),
|
.gap_4()
|
||||||
)
|
.child(render_import_settings_section())
|
||||||
|
.child(render_popular_settings_section(window, cx))
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,9 @@ use gpui::{
|
||||||
};
|
};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use settings::{Settings, SettingsStore, VsCodeSettingsSource, update_settings_file};
|
use settings::{SettingsStore, VsCodeSettingsSource};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use theme::{ThemeMode, ThemeSettings};
|
use ui::{FluentBuilder, KeyBinding, Vector, VectorName, prelude::*, rems_from_px};
|
||||||
use ui::{
|
|
||||||
Divider, FluentBuilder, Headline, KeyBinding, ParentElement as _, StatefulInteractiveElement,
|
|
||||||
ToggleButtonGroup, ToggleButtonSimple, Vector, VectorName, prelude::*, rems_from_px,
|
|
||||||
};
|
|
||||||
use workspace::{
|
use workspace::{
|
||||||
AppState, Workspace, WorkspaceId,
|
AppState, Workspace, WorkspaceId,
|
||||||
dock::DockPosition,
|
dock::DockPosition,
|
||||||
|
@ -24,6 +20,7 @@ use workspace::{
|
||||||
open_new, with_active_or_new_workspace,
|
open_new, with_active_or_new_workspace,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod basics_page;
|
||||||
mod editing_page;
|
mod editing_page;
|
||||||
mod welcome;
|
mod welcome;
|
||||||
|
|
||||||
|
@ -205,23 +202,6 @@ pub fn show_onboarding_view(app_state: Arc<AppState>, cx: &mut App) -> Task<anyh
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_theme_selection(cx: &App) -> ThemeMode {
|
|
||||||
let settings = ThemeSettings::get_global(cx);
|
|
||||||
settings
|
|
||||||
.theme_selection
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|selection| selection.mode())
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_theme_selection(theme_mode: ThemeMode, cx: &App) {
|
|
||||||
let fs = <dyn Fs>::global(cx);
|
|
||||||
|
|
||||||
update_settings_file::<ThemeSettings>(fs, cx, move |settings, _| {
|
|
||||||
settings.set_mode(theme_mode);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
enum SelectedPage {
|
enum SelectedPage {
|
||||||
Basics,
|
Basics,
|
||||||
|
@ -246,7 +226,7 @@ impl Onboarding {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_page_nav(
|
fn render_nav_button(
|
||||||
&mut self,
|
&mut self,
|
||||||
page: SelectedPage,
|
page: SelectedPage,
|
||||||
_: &mut Window,
|
_: &mut Window,
|
||||||
|
@ -257,54 +237,119 @@ impl Onboarding {
|
||||||
SelectedPage::Editing => "Editing",
|
SelectedPage::Editing => "Editing",
|
||||||
SelectedPage::AiSetup => "AI Setup",
|
SelectedPage::AiSetup => "AI Setup",
|
||||||
};
|
};
|
||||||
|
|
||||||
let binding = match page {
|
let binding = match page {
|
||||||
SelectedPage::Basics => {
|
SelectedPage::Basics => {
|
||||||
KeyBinding::new(vec![gpui::Keystroke::parse("cmd-1").unwrap()], cx)
|
KeyBinding::new(vec![gpui::Keystroke::parse("cmd-1").unwrap()], cx)
|
||||||
|
.map(|kb| kb.size(rems_from_px(12.)))
|
||||||
}
|
}
|
||||||
SelectedPage::Editing => {
|
SelectedPage::Editing => {
|
||||||
KeyBinding::new(vec![gpui::Keystroke::parse("cmd-2").unwrap()], cx)
|
KeyBinding::new(vec![gpui::Keystroke::parse("cmd-2").unwrap()], cx)
|
||||||
|
.map(|kb| kb.size(rems_from_px(12.)))
|
||||||
}
|
}
|
||||||
SelectedPage::AiSetup => {
|
SelectedPage::AiSetup => {
|
||||||
KeyBinding::new(vec![gpui::Keystroke::parse("cmd-3").unwrap()], cx)
|
KeyBinding::new(vec![gpui::Keystroke::parse("cmd-3").unwrap()], cx)
|
||||||
|
.map(|kb| kb.size(rems_from_px(12.)))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let selected = self.selected_page == page;
|
let selected = self.selected_page == page;
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.id(text)
|
.id(text)
|
||||||
.rounded_sm()
|
.relative()
|
||||||
.child(text)
|
.w_full()
|
||||||
.child(binding)
|
|
||||||
.h_8()
|
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.px_2()
|
.px_2()
|
||||||
.py_0p5()
|
.py_0p5()
|
||||||
.w_full()
|
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.map(|this| {
|
.rounded_sm()
|
||||||
if selected {
|
.when(selected, |this| {
|
||||||
this.bg(Color::Selected.color(cx))
|
this.child(
|
||||||
.border_l_1()
|
div()
|
||||||
.border_color(Color::Accent.color(cx))
|
.h_4()
|
||||||
} else {
|
.w_px()
|
||||||
this.text_color(Color::Muted.color(cx))
|
.bg(cx.theme().colors().text_accent)
|
||||||
}
|
.absolute()
|
||||||
|
.left_0(),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.hover(|style| {
|
.hover(|style| style.bg(cx.theme().colors().element_hover))
|
||||||
|
.child(Label::new(text).map(|this| {
|
||||||
if selected {
|
if selected {
|
||||||
style.bg(Color::Selected.color(cx).opacity(0.6))
|
this.color(Color::Default)
|
||||||
} else {
|
} else {
|
||||||
style.bg(Color::Selected.color(cx).opacity(0.3))
|
this.color(Color::Muted)
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
|
.child(binding)
|
||||||
.on_click(cx.listener(move |this, _, _, cx| {
|
.on_click(cx.listener(move |this, _, _, cx| {
|
||||||
this.selected_page = page;
|
this.selected_page = page;
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_nav(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
v_flex()
|
||||||
|
.h_full()
|
||||||
|
.w(rems_from_px(220.))
|
||||||
|
.flex_shrink_0()
|
||||||
|
.gap_4()
|
||||||
|
.justify_between()
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.px_2()
|
||||||
|
.gap_4()
|
||||||
|
.child(Vector::square(VectorName::ZedLogo, rems(2.5)))
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.child(
|
||||||
|
Headline::new("Welcome to Zed").size(HeadlineSize::Small),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Label::new("The editor for what's next")
|
||||||
|
.color(Color::Muted)
|
||||||
|
.size(LabelSize::Small)
|
||||||
|
.italic(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.gap_4()
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.py_4()
|
||||||
|
.border_y_1()
|
||||||
|
.border_color(cx.theme().colors().border_variant.opacity(0.5))
|
||||||
|
.gap_1()
|
||||||
|
.children([
|
||||||
|
self.render_nav_button(SelectedPage::Basics, window, cx)
|
||||||
|
.into_element(),
|
||||||
|
self.render_nav_button(SelectedPage::Editing, window, cx)
|
||||||
|
.into_element(),
|
||||||
|
self.render_nav_button(SelectedPage::AiSetup, window, cx)
|
||||||
|
.into_element(),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
.child(Button::new("skip_all", "Skip All")),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Button::new("sign_in", "Sign In")
|
||||||
|
.style(ButtonStyle::Outlined)
|
||||||
|
.full_width(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn render_page(&mut self, window: &mut Window, cx: &mut Context<Self>) -> AnyElement {
|
fn render_page(&mut self, window: &mut Window, cx: &mut Context<Self>) -> AnyElement {
|
||||||
match self.selected_page {
|
match self.selected_page {
|
||||||
SelectedPage::Basics => self.render_basics_page(window, cx).into_any_element(),
|
SelectedPage::Basics => {
|
||||||
|
crate::basics_page::render_basics_page(window, cx).into_any_element()
|
||||||
|
}
|
||||||
SelectedPage::Editing => {
|
SelectedPage::Editing => {
|
||||||
crate::editing_page::render_editing_page(window, cx).into_any_element()
|
crate::editing_page::render_editing_page(window, cx).into_any_element()
|
||||||
}
|
}
|
||||||
|
@ -312,36 +357,6 @@ impl Onboarding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_basics_page(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
||||||
let theme_mode = read_theme_selection(cx);
|
|
||||||
|
|
||||||
v_flex().child(
|
|
||||||
h_flex().justify_between().child(Label::new("Theme")).child(
|
|
||||||
ToggleButtonGroup::single_row(
|
|
||||||
"theme-selector-onboarding",
|
|
||||||
[
|
|
||||||
ToggleButtonSimple::new("Light", |_, _, cx| {
|
|
||||||
write_theme_selection(ThemeMode::Light, cx)
|
|
||||||
}),
|
|
||||||
ToggleButtonSimple::new("Dark", |_, _, cx| {
|
|
||||||
write_theme_selection(ThemeMode::Dark, cx)
|
|
||||||
}),
|
|
||||||
ToggleButtonSimple::new("System", |_, _, cx| {
|
|
||||||
write_theme_selection(ThemeMode::System, cx)
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.selected_index(match theme_mode {
|
|
||||||
ThemeMode::Light => 0,
|
|
||||||
ThemeMode::Dark => 1,
|
|
||||||
ThemeMode::System => 2,
|
|
||||||
})
|
|
||||||
.style(ui::ToggleButtonGroupStyle::Outlined)
|
|
||||||
.button_width(rems_from_px(64.)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_ai_setup_page(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
fn render_ai_setup_page(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||||
div().child("ai setup page")
|
div().child("ai setup page")
|
||||||
}
|
}
|
||||||
|
@ -352,44 +367,27 @@ impl Render for Onboarding {
|
||||||
h_flex()
|
h_flex()
|
||||||
.image_cache(gpui::retain_all("onboarding-page"))
|
.image_cache(gpui::retain_all("onboarding-page"))
|
||||||
.key_context("onboarding-page")
|
.key_context("onboarding-page")
|
||||||
.px_24()
|
.size_full()
|
||||||
.py_12()
|
.bg(cx.theme().colors().editor_background)
|
||||||
.items_start()
|
|
||||||
.child(
|
.child(
|
||||||
v_flex()
|
h_flex()
|
||||||
.w_1_3()
|
.max_w(rems_from_px(1100.))
|
||||||
.h_full()
|
.size_full()
|
||||||
|
.m_auto()
|
||||||
|
.py_20()
|
||||||
|
.px_12()
|
||||||
|
.items_start()
|
||||||
|
.gap_12()
|
||||||
|
.child(self.render_nav(window, cx))
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
div()
|
||||||
.pt_0p5()
|
.pl_12()
|
||||||
.child(Vector::square(VectorName::ZedLogo, rems(2.)))
|
.border_l_1()
|
||||||
.child(
|
.border_color(cx.theme().colors().border_variant.opacity(0.5))
|
||||||
v_flex()
|
.size_full()
|
||||||
.left_1()
|
.child(self.render_page(window, cx)),
|
||||||
.items_center()
|
|
||||||
.child(Headline::new("Welcome to Zed"))
|
|
||||||
.child(
|
|
||||||
Label::new("The editor for what's next")
|
|
||||||
.color(Color::Muted)
|
|
||||||
.italic(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.p_1()
|
|
||||||
.child(Divider::horizontal())
|
|
||||||
.child(
|
|
||||||
v_flex().gap_1().children([
|
|
||||||
self.render_page_nav(SelectedPage::Basics, window, cx)
|
|
||||||
.into_element(),
|
|
||||||
self.render_page_nav(SelectedPage::Editing, window, cx)
|
|
||||||
.into_element(),
|
|
||||||
self.render_page_nav(SelectedPage::AiSetup, window, cx)
|
|
||||||
.into_element(),
|
|
||||||
]),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(div().child(Divider::vertical()).h_full())
|
|
||||||
.child(div().w_2_3().h_full().child(self.render_page(window, cx)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ use super::PopoverMenuHandle;
|
||||||
pub enum DropdownStyle {
|
pub enum DropdownStyle {
|
||||||
#[default]
|
#[default]
|
||||||
Solid,
|
Solid,
|
||||||
|
Outlined,
|
||||||
Ghost,
|
Ghost,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,6 +148,23 @@ impl Component for DropdownMenu {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
example_group_with_title(
|
||||||
|
"Styles",
|
||||||
|
vec![
|
||||||
|
single_example(
|
||||||
|
"Outlined",
|
||||||
|
DropdownMenu::new("outlined", "Outlined Dropdown", menu.clone())
|
||||||
|
.style(DropdownStyle::Outlined)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
single_example(
|
||||||
|
"Ghost",
|
||||||
|
DropdownMenu::new("ghost", "Ghost Dropdown", menu.clone())
|
||||||
|
.style(DropdownStyle::Ghost)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
example_group_with_title(
|
example_group_with_title(
|
||||||
"States",
|
"States",
|
||||||
vec![single_example(
|
vec![single_example(
|
||||||
|
@ -170,10 +188,13 @@ pub struct DropdownTriggerStyle {
|
||||||
impl DropdownTriggerStyle {
|
impl DropdownTriggerStyle {
|
||||||
pub fn for_style(style: DropdownStyle, cx: &App) -> Self {
|
pub fn for_style(style: DropdownStyle, cx: &App) -> Self {
|
||||||
let colors = cx.theme().colors();
|
let colors = cx.theme().colors();
|
||||||
|
|
||||||
let bg = match style {
|
let bg = match style {
|
||||||
DropdownStyle::Solid => colors.editor_background,
|
DropdownStyle::Solid => colors.editor_background,
|
||||||
|
DropdownStyle::Outlined => colors.surface_background,
|
||||||
DropdownStyle::Ghost => colors.ghost_element_background,
|
DropdownStyle::Ghost => colors.ghost_element_background,
|
||||||
};
|
};
|
||||||
|
|
||||||
Self { bg }
|
Self { bg }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,17 +265,24 @@ impl RenderOnce for DropdownMenuTrigger {
|
||||||
let disabled = self.disabled;
|
let disabled = self.disabled;
|
||||||
|
|
||||||
let style = DropdownTriggerStyle::for_style(self.style, cx);
|
let style = DropdownTriggerStyle::for_style(self.style, cx);
|
||||||
|
let is_outlined = matches!(self.style, DropdownStyle::Outlined);
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.id("dropdown-menu-trigger")
|
.id("dropdown-menu-trigger")
|
||||||
.justify_between()
|
.min_w_20()
|
||||||
.rounded_sm()
|
|
||||||
.bg(style.bg)
|
|
||||||
.pl_2()
|
.pl_2()
|
||||||
.pr_1p5()
|
.pr_1p5()
|
||||||
.py_0p5()
|
.py_0p5()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.min_w_20()
|
.justify_between()
|
||||||
|
.rounded_sm()
|
||||||
|
.bg(style.bg)
|
||||||
|
.hover(|s| s.bg(cx.theme().colors().element_hover))
|
||||||
|
.when(is_outlined, |this| {
|
||||||
|
this.border_1()
|
||||||
|
.border_color(cx.theme().colors().border)
|
||||||
|
.overflow_hidden()
|
||||||
|
})
|
||||||
.map(|el| {
|
.map(|el| {
|
||||||
if self.full_width {
|
if self.full_width {
|
||||||
el.w_full()
|
el.w_full()
|
||||||
|
|
|
@ -1,17 +1,24 @@
|
||||||
use gpui::ClickEvent;
|
use gpui::ClickEvent;
|
||||||
|
|
||||||
use crate::{Divider, IconButtonShape, prelude::*};
|
use crate::{IconButtonShape, prelude::*};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum NumericStepperStyle {
|
||||||
|
Outlined,
|
||||||
|
#[default]
|
||||||
|
Ghost,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(IntoElement, RegisterComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct NumericStepper {
|
pub struct NumericStepper {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
value: SharedString,
|
value: SharedString,
|
||||||
|
style: NumericStepperStyle,
|
||||||
on_decrement: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
|
on_decrement: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
|
||||||
on_increment: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
|
on_increment: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
|
||||||
/// Whether to reserve space for the reset button.
|
/// Whether to reserve space for the reset button.
|
||||||
reserve_space_for_reset: bool,
|
reserve_space_for_reset: bool,
|
||||||
on_reset: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
|
on_reset: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
|
||||||
border: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NumericStepper {
|
impl NumericStepper {
|
||||||
|
@ -24,14 +31,19 @@ impl NumericStepper {
|
||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
value: value.into(),
|
value: value.into(),
|
||||||
|
style: NumericStepperStyle::default(),
|
||||||
on_decrement: Box::new(on_decrement),
|
on_decrement: Box::new(on_decrement),
|
||||||
on_increment: Box::new(on_increment),
|
on_increment: Box::new(on_increment),
|
||||||
border: false,
|
|
||||||
reserve_space_for_reset: false,
|
reserve_space_for_reset: false,
|
||||||
on_reset: None,
|
on_reset: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn style(mut self, style: NumericStepperStyle) -> Self {
|
||||||
|
self.style = style;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn reserve_space_for_reset(mut self, reserve_space_for_reset: bool) -> Self {
|
pub fn reserve_space_for_reset(mut self, reserve_space_for_reset: bool) -> Self {
|
||||||
self.reserve_space_for_reset = reserve_space_for_reset;
|
self.reserve_space_for_reset = reserve_space_for_reset;
|
||||||
self
|
self
|
||||||
|
@ -44,11 +56,6 @@ impl NumericStepper {
|
||||||
self.on_reset = Some(Box::new(on_reset));
|
self.on_reset = Some(Box::new(on_reset));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn border(mut self) -> Self {
|
|
||||||
self.border = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderOnce for NumericStepper {
|
impl RenderOnce for NumericStepper {
|
||||||
|
@ -56,6 +63,8 @@ impl RenderOnce for NumericStepper {
|
||||||
let shape = IconButtonShape::Square;
|
let shape = IconButtonShape::Square;
|
||||||
let icon_size = IconSize::Small;
|
let icon_size = IconSize::Small;
|
||||||
|
|
||||||
|
let is_outlined = matches!(self.style, NumericStepperStyle::Outlined);
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.id(self.id)
|
.id(self.id)
|
||||||
.gap_1()
|
.gap_1()
|
||||||
|
@ -81,31 +90,65 @@ impl RenderOnce for NumericStepper {
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
.when(self.border, |this| {
|
|
||||||
this.border_1().border_color(cx.theme().colors().border)
|
|
||||||
})
|
|
||||||
.px_1()
|
|
||||||
.rounded_sm()
|
.rounded_sm()
|
||||||
.bg(cx.theme().colors().editor_background)
|
.map(|this| {
|
||||||
.child(
|
if is_outlined {
|
||||||
IconButton::new("decrement", IconName::Dash)
|
this.overflow_hidden()
|
||||||
.shape(shape)
|
.bg(cx.theme().colors().surface_background)
|
||||||
.icon_size(icon_size)
|
.border_1()
|
||||||
.on_click(self.on_decrement),
|
.border_color(cx.theme().colors().border)
|
||||||
)
|
} else {
|
||||||
.when(self.border, |this| {
|
this.px_1().bg(cx.theme().colors().editor_background)
|
||||||
this.child(Divider::vertical().color(super::DividerColor::Border))
|
}
|
||||||
})
|
})
|
||||||
.child(Label::new(self.value))
|
.map(|decrement| {
|
||||||
.when(self.border, |this| {
|
if is_outlined {
|
||||||
this.child(Divider::vertical().color(super::DividerColor::Border))
|
decrement.child(
|
||||||
|
h_flex()
|
||||||
|
.id("decrement_button")
|
||||||
|
.p_1p5()
|
||||||
|
.size_full()
|
||||||
|
.justify_center()
|
||||||
|
.hover(|s| s.bg(cx.theme().colors().element_hover))
|
||||||
|
.border_r_1()
|
||||||
|
.border_color(cx.theme().colors().border)
|
||||||
|
.child(Icon::new(IconName::Dash).size(IconSize::Small))
|
||||||
|
.on_click(self.on_decrement),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
decrement.child(
|
||||||
|
IconButton::new("decrement", IconName::Dash)
|
||||||
|
.shape(shape)
|
||||||
|
.icon_size(icon_size)
|
||||||
|
.on_click(self.on_decrement),
|
||||||
|
)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.child(
|
.when(is_outlined, |this| this)
|
||||||
IconButton::new("increment", IconName::Plus)
|
.child(Label::new(self.value).mx_3())
|
||||||
.shape(shape)
|
.map(|increment| {
|
||||||
.icon_size(icon_size)
|
if is_outlined {
|
||||||
.on_click(self.on_increment),
|
increment.child(
|
||||||
),
|
h_flex()
|
||||||
|
.id("increment_button")
|
||||||
|
.p_1p5()
|
||||||
|
.size_full()
|
||||||
|
.justify_center()
|
||||||
|
.hover(|s| s.bg(cx.theme().colors().element_hover))
|
||||||
|
.border_l_1()
|
||||||
|
.border_color(cx.theme().colors().border)
|
||||||
|
.child(Icon::new(IconName::Plus).size(IconSize::Small))
|
||||||
|
.on_click(self.on_increment),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
increment.child(
|
||||||
|
IconButton::new("increment", IconName::Dash)
|
||||||
|
.shape(shape)
|
||||||
|
.icon_size(icon_size)
|
||||||
|
.on_click(self.on_increment),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,7 +159,7 @@ impl Component for NumericStepper {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name() -> &'static str {
|
fn name() -> &'static str {
|
||||||
"NumericStepper"
|
"Numeric Stepper"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sort_name() -> &'static str {
|
fn sort_name() -> &'static str {
|
||||||
|
@ -124,33 +167,39 @@ impl Component for NumericStepper {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn description() -> Option<&'static str> {
|
fn description() -> Option<&'static str> {
|
||||||
Some("A button used to increment or decrement a numeric value. ")
|
Some("A button used to increment or decrement a numeric value.")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||||
Some(
|
Some(
|
||||||
v_flex()
|
v_flex()
|
||||||
.child(single_example(
|
.gap_6()
|
||||||
"Borderless",
|
.children(vec![example_group_with_title(
|
||||||
NumericStepper::new(
|
"Styles",
|
||||||
"numeric-stepper-component-preview",
|
vec![
|
||||||
"10",
|
single_example(
|
||||||
move |_, _, _| {},
|
"Default",
|
||||||
move |_, _, _| {},
|
NumericStepper::new(
|
||||||
)
|
"numeric-stepper-component-preview",
|
||||||
.into_any_element(),
|
"10",
|
||||||
))
|
move |_, _, _| {},
|
||||||
.child(single_example(
|
move |_, _, _| {},
|
||||||
"Border",
|
)
|
||||||
NumericStepper::new(
|
.into_any_element(),
|
||||||
"numeric-stepper-with-border-component-preview",
|
),
|
||||||
"10",
|
single_example(
|
||||||
move |_, _, _| {},
|
"Outlined",
|
||||||
move |_, _, _| {},
|
NumericStepper::new(
|
||||||
)
|
"numeric-stepper-with-border-component-preview",
|
||||||
.border()
|
"10",
|
||||||
.into_any_element(),
|
move |_, _, _| {},
|
||||||
))
|
move |_, _, _| {},
|
||||||
|
)
|
||||||
|
.style(NumericStepperStyle::Outlined)
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)])
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue