feat: app settings #11
@@ -22,7 +22,8 @@ use gpui_component::separator::Separator;
|
||||
use gpui_component::setting::NumberFieldOptions;
|
||||
use gpui_component::switch::Switch;
|
||||
use gpui_component::{
|
||||
ActiveTheme, IconName, IndexPath, Theme, ThemeMode, ThemeRegistry, WindowExt, h_flex, v_flex,
|
||||
ActiveTheme, IconName, IndexPath, Sizable, Theme, ThemeMode, ThemeRegistry, WindowExt, h_flex,
|
||||
v_flex,
|
||||
};
|
||||
use nostr::prelude::RelayUrl;
|
||||
use settings::{AppearanceMode, Settings, SettingsStore};
|
||||
@@ -78,7 +79,7 @@ impl SettingsControls {
|
||||
let settings = store.read(cx).settings().clone();
|
||||
|
||||
let appearance_options = vec![
|
||||
SelectOption::new("system", "Follow system"),
|
||||
SelectOption::new("system", "System"),
|
||||
SelectOption::new("light", "Light"),
|
||||
SelectOption::new("dark", "Dark"),
|
||||
];
|
||||
@@ -275,7 +276,6 @@ impl SettingsControls {
|
||||
/// Open the Settings dialog.
|
||||
pub fn open(window: &mut Window, cx: &mut App) {
|
||||
let controls = Rc::new(SettingsControls::new(window, cx));
|
||||
|
||||
let store = SettingsStore::global(cx);
|
||||
let window_handle = window.window_handle();
|
||||
let store_subscription = cx.observe(&store, move |_, cx| {
|
||||
@@ -290,7 +290,7 @@ pub fn open(window: &mut Window, cx: &mut App) {
|
||||
let dialog_state = dialog_state.clone();
|
||||
dialog
|
||||
.title("Settings")
|
||||
.width(px(640.))
|
||||
.width(px(650.))
|
||||
.h(px(560.))
|
||||
.child(settings_view(&dialog_state.0, cx))
|
||||
});
|
||||
@@ -303,8 +303,9 @@ fn settings_view(controls: &SettingsControls, cx: &mut App) -> impl IntoElement
|
||||
let settings = store.read(cx).settings().clone();
|
||||
|
||||
v_flex()
|
||||
.w_full()
|
||||
.mt_2()
|
||||
.gap_4()
|
||||
.w_full()
|
||||
.child(appearance_section(controls, cx))
|
||||
.child(Separator::horizontal())
|
||||
.child(theme_section(&settings, controls, cx))
|
||||
@@ -319,7 +320,7 @@ fn appearance_section(controls: &SettingsControls, cx: &App) -> impl IntoElement
|
||||
v_flex().w_full().gap_3().child(setting_row(
|
||||
cx,
|
||||
"Appearance",
|
||||
"How the app picks its appearance: follow the system, or always light or dark.",
|
||||
"Choose whether the app follows the system theme or uses a light/dark theme.",
|
||||
Select::new(&controls.appearance).w_full(),
|
||||
))
|
||||
}
|
||||
@@ -328,47 +329,47 @@ fn appearance_section(controls: &SettingsControls, cx: &App) -> impl IntoElement
|
||||
/// the visual tweaks the application customizes at startup.
|
||||
fn theme_section(settings: &Settings, controls: &SettingsControls, cx: &App) -> impl IntoElement {
|
||||
v_flex()
|
||||
.w_full()
|
||||
.gap_3()
|
||||
.w_full()
|
||||
.child(setting_row(
|
||||
cx,
|
||||
"Light theme",
|
||||
"The light theme used when the appearance is light.",
|
||||
"Light Theme",
|
||||
"The theme to use when the appearance is light.",
|
||||
Select::new(&controls.light_theme).w_full(),
|
||||
))
|
||||
.child(setting_row(
|
||||
cx,
|
||||
"Dark theme",
|
||||
"The dark theme used when the appearance is dark.",
|
||||
"Dark Theme",
|
||||
"The theme to use when the appearance is dark.",
|
||||
Select::new(&controls.dark_theme).w_full(),
|
||||
))
|
||||
.child(setting_row(
|
||||
cx,
|
||||
"Base font size",
|
||||
"The base font size in pixels.",
|
||||
"UI Font Size",
|
||||
"Font size for the UI.",
|
||||
NumberInput::new(&controls.font_size).w_full(),
|
||||
))
|
||||
.child(setting_row(
|
||||
cx,
|
||||
"Monospace font size",
|
||||
"The monospace font size in pixels.",
|
||||
"Editor Font Size",
|
||||
"Font size for editor text.",
|
||||
NumberInput::new(&controls.mono_font_size).w_full(),
|
||||
))
|
||||
.child(setting_row(
|
||||
cx,
|
||||
"Corner radius",
|
||||
"The corner radius of general elements in pixels.",
|
||||
"Corner Radius",
|
||||
"The corner radius for UI elements.",
|
||||
NumberInput::new(&controls.radius).w_full(),
|
||||
))
|
||||
.child(setting_row(
|
||||
cx,
|
||||
"Large corner radius",
|
||||
"The corner radius of large elements (dialogs, notifications) in pixels.",
|
||||
"Large Corner Radius",
|
||||
"The corner radius for large UI elements (dialogs, notifications).",
|
||||
NumberInput::new(&controls.radius_lg).w_full(),
|
||||
))
|
||||
.child(setting_row(
|
||||
cx,
|
||||
"Focus ring",
|
||||
"Focus Ring",
|
||||
"Draw a ring around focused controls.",
|
||||
Switch::new("focus-ring")
|
||||
.checked(settings.theme.focus_ring)
|
||||
@@ -383,7 +384,7 @@ fn theme_section(settings: &Settings, controls: &SettingsControls, cx: &App) ->
|
||||
.child(setting_row(
|
||||
cx,
|
||||
"Shadows",
|
||||
"Render shadows.",
|
||||
"The shadow effect for UI elements.",
|
||||
Switch::new("shadows")
|
||||
.checked(settings.theme.shadow)
|
||||
.on_click(move |checked: &bool, _window, cx| {
|
||||
@@ -406,8 +407,8 @@ fn grasp_servers_section(
|
||||
|
||||
v_flex().w_full().gap_3().child(setting_block(
|
||||
cx,
|
||||
"Default servers",
|
||||
"Servers offered when you haven't published a grasp list (kind 10317).",
|
||||
"Grasp Servers",
|
||||
"Servers used to host your git repositories via the Grasp protocol",
|
||||
grasp_server_editor(&servers, controls, cx),
|
||||
))
|
||||
}
|
||||
@@ -500,14 +501,14 @@ fn repositories_section(
|
||||
.gap_3()
|
||||
.child(setting_block(
|
||||
cx,
|
||||
"Scan directories",
|
||||
"Scan Directories",
|
||||
"Directories scanned for local git repositories.",
|
||||
scan_paths_editor(&scan_paths, cx),
|
||||
))
|
||||
.child(setting_block(
|
||||
cx,
|
||||
"Default folder",
|
||||
"The folder the Create Repository dialog defaults to.",
|
||||
"Default Folder",
|
||||
"The folder for newly created repositories.",
|
||||
folder_selector(controls),
|
||||
))
|
||||
}
|
||||
@@ -554,11 +555,12 @@ fn scan_paths_editor(scan_paths: &[PathBuf], cx: &App) -> impl IntoElement {
|
||||
)
|
||||
}))
|
||||
.child(
|
||||
h_flex().w_full().justify_end().child(
|
||||
h_flex().justify_end().items_center().child(
|
||||
Button::new("settings-add-path")
|
||||
.icon(IconName::FolderOpen)
|
||||
.ghost()
|
||||
.tooltip("Add directory")
|
||||
.icon(IconName::Plus)
|
||||
.label("Add directory")
|
||||
.secondary()
|
||||
.small()
|
||||
.on_click(move |_event, _window, cx| add_scan_path(cx)),
|
||||
),
|
||||
)
|
||||
@@ -579,7 +581,7 @@ fn folder_selector(controls: &SettingsControls) -> impl IntoElement {
|
||||
)
|
||||
.child(
|
||||
Button::new("settings-choose-folder")
|
||||
.icon(IconName::FolderOpen)
|
||||
.icon(IconName::Folder)
|
||||
.ghost()
|
||||
.tooltip("Choose folder")
|
||||
.on_click(move |_event, window, cx| {
|
||||
@@ -627,7 +629,7 @@ fn add_scan_path(cx: &mut App) {
|
||||
files: false,
|
||||
directories: true,
|
||||
multiple: true,
|
||||
prompt: Some("Choose directories to scan".into()),
|
||||
prompt: Some("Choose directories".into()),
|
||||
});
|
||||
|
||||
cx.spawn(async move |cx| {
|
||||
|
||||
Reference in New Issue
Block a user