Add general new tab settings

This commit is contained in:
2026-05-08 03:13:37 -04:00
parent 6750f60d52
commit 4bdbf5e0c5
14 changed files with 369 additions and 22 deletions
@@ -3,6 +3,7 @@ mod bookmarks;
mod download_actions;
mod download_labels;
mod downloads;
mod general;
mod plugin_catalog;
mod plugin_details;
mod plugins;
@@ -51,6 +52,7 @@ impl ElyShell {
}
"ely://about" => self.render_about_page(snapshot),
"ely://settings" => self.render_settings_page(snapshot, cx),
"ely://settings/general" => self.render_general_page(snapshot, cx),
"ely://settings/sidebar-tabs" => self.render_sidebar_tabs_page(snapshot, cx),
"ely://settings/search" => self.render_search_page(snapshot, cx),
"ely://settings/spaces" => self.render_spaces_page(snapshot, cx),
@@ -0,0 +1,215 @@
use ely_browser_core::BrowserSnapshot;
use ely_design_system::colors;
use ely_domain::NewTabDestination;
use gpui::{AnyElement, Context, IntoElement, ParentElement, Styled, div, px, rgb};
use gpui_component::{
IconName, Selectable, Sizable, StyledExt,
button::{Button, ButtonVariants},
scroll::ScrollableElement,
};
use super::{ElyShell, render_canvas_surface};
impl ElyShell {
pub(super) fn render_general_page(
&mut self,
snapshot: &BrowserSnapshot,
cx: &mut Context<Self>,
) -> AnyElement {
render_canvas_surface(
div()
.size_full()
.p_8()
.flex()
.flex_col()
.gap_5()
.child(render_general_header(snapshot))
.child(render_general_summary(snapshot.new_tab_destination))
.child(render_new_tab_destinations(snapshot.new_tab_destination, cx)),
)
}
}
fn render_general_header(snapshot: &BrowserSnapshot) -> AnyElement {
div()
.flex()
.items_end()
.justify_between()
.gap_4()
.child(
div()
.min_w_0()
.flex()
.flex_col()
.gap_2()
.child(div().text_size(px(26.0)).text_color(rgb(colors::INK)).child("General"))
.child(
div()
.text_sm()
.truncate()
.text_color(rgb(colors::MUTED))
.child(format!("Profile: {}", snapshot.active_profile_name)),
),
)
.child(
div()
.flex()
.items_center()
.gap_2()
.text_xs()
.font_semibold()
.text_color(rgb(colors::MUTED))
.child(IconName::Settings2)
.child(snapshot.new_tab_destination.name()),
)
.into_any_element()
}
fn render_general_summary(destination: NewTabDestination) -> AnyElement {
div()
.rounded_md()
.border_1()
.border_color(rgb(colors::HAIRLINE))
.bg(rgb(colors::CANVAS_SOFT))
.px_4()
.py_3()
.flex()
.items_center()
.justify_between()
.gap_4()
.child(
div()
.min_w_0()
.flex()
.items_center()
.gap_3()
.child(div().text_color(rgb(colors::PRIMARY)).child(destination_icon(destination)))
.child(
div()
.min_w_0()
.flex()
.flex_col()
.gap_1()
.child(
div()
.text_sm()
.font_semibold()
.text_color(rgb(colors::INK))
.child(format!("New Tab opens {}", destination.name())),
)
.child(
div()
.text_xs()
.truncate()
.text_color(rgb(colors::MUTED))
.child(destination.detail()),
),
),
)
.child(
div().text_xs().font_semibold().text_color(rgb(colors::SUCCESS)).child("Saved locally"),
)
.into_any_element()
}
fn render_new_tab_destinations(
active_destination: NewTabDestination,
cx: &mut Context<ElyShell>,
) -> AnyElement {
div()
.flex_1()
.min_h_0()
.flex()
.flex_col()
.overflow_y_scrollbar()
.border_t_1()
.border_color(rgb(colors::HAIRLINE))
.children(NewTabDestination::ALL.iter().copied().enumerate().map(|(index, destination)| {
render_new_tab_destination_row(index, destination, active_destination, cx)
}))
.into_any_element()
}
fn render_new_tab_destination_row(
index: usize,
destination: NewTabDestination,
active_destination: NewTabDestination,
cx: &mut Context<ElyShell>,
) -> AnyElement {
let selected = destination == active_destination;
div()
.py_3()
.border_b_1()
.border_color(rgb(colors::HAIRLINE))
.flex()
.items_center()
.justify_between()
.gap_4()
.child(
div()
.min_w_0()
.flex()
.items_center()
.gap_3()
.child(
div()
.text_color(rgb(destination_icon_color(selected)))
.child(destination_status_icon(destination, selected)),
)
.child(
div()
.min_w_0()
.flex()
.flex_col()
.gap_1()
.child(
div()
.text_sm()
.font_semibold()
.truncate()
.text_color(rgb(colors::INK))
.child(destination.name()),
)
.child(
div()
.text_xs()
.truncate()
.text_color(rgb(colors::MUTED))
.child(destination.detail()),
),
),
)
.child(
Button::new(("new-tab-destination", index))
.ghost()
.xsmall()
.selected(selected)
.label(destination_button_label(selected))
.tooltip(destination.name())
.on_click(cx.listener(move |shell, _, _, cx| {
shell.set_new_tab_destination(destination, cx);
})),
)
.into_any_element()
}
fn destination_icon(destination: NewTabDestination) -> IconName {
match destination {
NewTabDestination::ElyNewTab => IconName::Plus,
NewTabDestination::Bookmarks => IconName::BookOpen,
NewTabDestination::ReadingList => IconName::Inbox,
}
}
fn destination_status_icon(destination: NewTabDestination, selected: bool) -> IconName {
if selected { IconName::CircleCheck } else { destination_icon(destination) }
}
fn destination_icon_color(selected: bool) -> u32 {
if selected { colors::PRIMARY } else { colors::MUTED_SOFT }
}
fn destination_button_label(selected: bool) -> &'static str {
if selected { "Active" } else { "Select" }
}
@@ -18,6 +18,12 @@ struct SettingsRoute {
}
const SETTINGS_ROUTES: &[SettingsRoute] = &[
SettingsRoute {
icon: IconName::Settings2,
title: "General",
detail: "New Tab destination and browser startup defaults.",
route: "ely://settings/general",
},
SettingsRoute {
icon: IconName::LayoutDashboard,
title: "Sidebar & Tabs",
+18 -2
View File
@@ -6,7 +6,10 @@ mod site_permissions;
mod splits;
use ely_browser_core::{BrowserCore, InitialBrowserConfig};
use ely_domain::{ArchivePolicy, CommandIntent, ProfileId, SearchEngine, SpaceId, TabId, UrlText};
use ely_domain::{
ArchivePolicy, CommandIntent, NewTabDestination, ProfileId, SearchEngine, SpaceId, TabId,
UrlText,
};
use gpui::{App, AppContext, Context, Entity, FocusHandle, Focusable, Subscription, Window};
use gpui_component::input::{InputEvent, InputState, SelectAll};
@@ -101,7 +104,13 @@ impl ElyShell {
}
fn open_new_tab(&mut self, window: &mut Window, cx: &mut Context<Self>) {
self.open_internal_tab("ely://new-tab", window, cx);
if let ShellState::Ready(core) = &mut self.state
&& core.open_new_tab().is_ok()
{
self.sync_address_input(window, cx);
self.focus_address_bar(window, cx);
cx.notify();
}
}
fn open_downloads(&mut self, window: &mut Window, cx: &mut Context<Self>) {
@@ -271,6 +280,13 @@ impl ElyShell {
}
}
fn set_new_tab_destination(&mut self, destination: NewTabDestination, cx: &mut Context<Self>) {
if let ShellState::Ready(core) = &mut self.state {
core.set_new_tab_destination(destination);
cx.notify();
}
}
fn archive_idle_tabs_now(&mut self, cx: &mut Context<Self>) {
if let ShellState::Ready(core) = &mut self.state
&& core.archive_idle_tabs(std::time::SystemTime::now()).is_ok()