diff --git a/crates/onboarding/src/basics_page.rs b/crates/onboarding/src/basics_page.rs index 11a20dfd77..44fa91c41b 100644 --- a/crates/onboarding/src/basics_page.rs +++ b/crates/onboarding/src/basics_page.rs @@ -1,3 +1,4 @@ +use std::path::Path; use std::sync::Arc; use std::time::Duration; @@ -5,7 +6,10 @@ use client::{Client, TelemetrySettings, UserStore, zed_urls}; use cloud_api_types::Plan; use collections::HashMap; use fs::Fs; -use gpui::{Action, Animation, AnimationExt, App, Entity, IntoElement, TaskExt, pulsating_between}; +use gpui::{ + Action, Animation, AnimationExt, App, Entity, ImageSource, IntoElement, ObjectFit, + PathPromptOptions, Resource, TaskExt, img, pulsating_between, +}; use project::agent_server_store::AllAgentServersSettings; use project::project_settings::ProjectSettings; use project::{AgentRegistryStore, RegistryAgent}; @@ -15,7 +19,7 @@ use settings::{ use theme::{Appearance, SystemAppearance, ThemeRegistry}; use theme_settings::{ThemeAppearanceMode, ThemeName, ThemeSelection, ThemeSettings}; use ui::{ - AgentSetupButton, Divider, StatefulInteractiveElement, SwitchField, TintColor, + AgentSetupButton, Button, Divider, StatefulInteractiveElement, SwitchField, TintColor, ToggleButtonGroup, ToggleButtonGroupSize, ToggleButtonSimple, ToggleButtonWithIcon, Tooltip, prelude::*, }; @@ -242,6 +246,95 @@ fn render_theme_section(tab_index: &mut isize, cx: &mut App) -> impl IntoElement } } +fn render_background_section(tab_index: &mut isize, cx: &mut App) -> impl IntoElement { + let current_path = cx + .try_global::() + .and_then(|store| store.merged_settings().background.clone()) + .and_then(|background| background.path) + .filter(|path| !path.is_empty()); + let has_background = current_path.is_some(); + let colors = cx.theme().colors(); + let fs = ::global(cx); + + let select_button = { + let fs = fs.clone(); + Button::new("onboarding-background-select", "Select Image…") + .tab_index({ + *tab_index += 1; + *tab_index - 1 + }) + .on_click(move |_, _window, cx| { + let receiver = cx.prompt_for_paths(PathPromptOptions { + files: true, + directories: false, + multiple: false, + prompt: None, + }); + let fs = fs.clone(); + cx.spawn(async move |cx| { + let Ok(Ok(Some(paths))) = receiver.await else { + return; + }; + let Some(path) = paths.into_iter().next() else { + return; + }; + let path = path.to_string_lossy().to_string(); + cx.update(|cx| { + update_settings_file(fs, cx, move |settings, _cx| { + settings.background.get_or_insert_default().path = Some(path); + }); + telemetry::event!("Welcome Background Changed", set = true); + }); + }) + .detach(); + }) + }; + + let clear_button = { + let fs = fs.clone(); + Button::new("onboarding-background-clear", "Clear") + .tab_index({ + *tab_index += 1; + *tab_index - 1 + }) + .on_click(move |_, _, cx| { + update_settings_file(fs.clone(), cx, |settings, _cx| { + settings.background.get_or_insert_default().path = None; + }); + telemetry::event!("Welcome Background Changed", set = false); + }) + }; + + let preview = match current_path { + Some(path) => img(ImageSource::Resource(Resource::Path(Arc::from(Path::new(&path))))) + .w_full() + .h(rems_from_px(120.0_f32)) + .object_fit(ObjectFit::Cover) + .rounded_md() + .border_1() + .border_color(colors.border) + .into_any_element(), + None => Label::new("No background image yet — pick one to show it behind the editor.") + .color(Color::Muted) + .into_any_element(), + }; + + v_flex() + .gap_2() + .child( + h_flex() + .justify_between() + .child(Label::new("Background")) + .child( + h_flex() + .gap_2() + .child(select_button) + .when(has_background, |this| this.child(clear_button)), + ), + ) + .child(preview) +} + fn render_telemetry_section(tab_index: &mut isize, cx: &App) -> impl IntoElement { let fs = ::global(cx); @@ -720,6 +813,7 @@ pub(crate) fn render_basics_page(user_store: &Entity, cx: &mut App) - .id("basics-page") .gap_6() .child(render_theme_section(&mut tab_index, cx)) + .child(render_background_section(&mut tab_index, cx)) .child(render_base_keymap_section(&mut tab_index, cx)) .child(render_ai_section(user_store, cx)) .child(render_import_settings_section(&mut tab_index, cx))