Add Sidebar / Layout cards to appearance form
Below the appearance rows the Appearance form now exposes the design's "Sidebar / Layout" section: serif "Layout" sub-headline plus a 2-up preview-card grid wired to the active space's sidebar_width — Single column lands on DEFAULT_SIDEBAR_WIDTH_PX, Compact lands on COLLAPSED_SIDEBAR_WIDTH_PX. Each card draws a miniature sidebar + canvas preview so the choice reads at a glance. The shell exposes a new set_active_sidebar_width helper alongside the existing toggle so the cards mutate state without re-implementing the toggle logic. The "Hidden on hover" preset from the design is omitted until that mode actually ships — no placeholder option. The cards live in chrome::appearance_layout_cards so appearance_form stays under 500 lines.
This commit is contained in:
@@ -8,6 +8,8 @@ use gpui::{
|
||||
};
|
||||
use gpui_component::{IconName, scroll::ScrollableElement};
|
||||
|
||||
use super::appearance_layout_cards::render_sidebar_layout_section;
|
||||
|
||||
use crate::shell::ElyShell;
|
||||
use crate::shell::chrome::SERIF_FAMILY;
|
||||
|
||||
@@ -31,7 +33,8 @@ pub(crate) fn render_appearance_form(
|
||||
.gap(px(28.0))
|
||||
.child(render_header())
|
||||
.child(render_wallpaper_grid(snapshot, cx))
|
||||
.child(render_appearance_rows(snapshot, cx)),
|
||||
.child(render_appearance_rows(snapshot, cx))
|
||||
.child(render_sidebar_layout_section(snapshot, cx)),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
use ely_browser_core::BrowserSnapshot;
|
||||
use ely_design_system::colors;
|
||||
use ely_domain::{COLLAPSED_SIDEBAR_WIDTH_PX, DEFAULT_SIDEBAR_WIDTH_PX};
|
||||
use gpui::{
|
||||
AnyElement, Context, FontWeight, InteractiveElement, IntoElement, ParentElement, SharedString,
|
||||
StatefulInteractiveElement, Styled, div, prelude::FluentBuilder, px, rgb, rgba,
|
||||
};
|
||||
|
||||
use crate::shell::ElyShell;
|
||||
use crate::shell::chrome::SERIF_FAMILY;
|
||||
|
||||
pub(crate) fn render_sidebar_layout_section(
|
||||
snapshot: &BrowserSnapshot,
|
||||
cx: &mut Context<ElyShell>,
|
||||
) -> AnyElement {
|
||||
let active_width = snapshot
|
||||
.spaces
|
||||
.iter()
|
||||
.find(|space| space.id() == &snapshot.active_space_id)
|
||||
.map(|space| space.sidebar_width_px())
|
||||
.unwrap_or(DEFAULT_SIDEBAR_WIDTH_PX);
|
||||
let compact = active_width <= COLLAPSED_SIDEBAR_WIDTH_PX;
|
||||
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap(px(14.0))
|
||||
.pt(px(8.0))
|
||||
.child(
|
||||
div()
|
||||
.text_size(px(11.0))
|
||||
.text_color(rgb(colors::INK_4))
|
||||
.child("SIDEBAR"),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.font_family(SERIF_FAMILY)
|
||||
.text_size(px(22.0))
|
||||
.font_weight(FontWeight(400.0))
|
||||
.text_color(rgb(colors::INK))
|
||||
.child("Layout"),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.grid()
|
||||
.grid_cols(2)
|
||||
.gap(px(10.0))
|
||||
.child(render_layout_card(
|
||||
"Single column",
|
||||
"Default · workspace + tabs.",
|
||||
!compact,
|
||||
LayoutMode::Single,
|
||||
cx,
|
||||
))
|
||||
.child(render_layout_card(
|
||||
"Compact",
|
||||
"Icons-only with launcher rail.",
|
||||
compact,
|
||||
LayoutMode::Compact,
|
||||
cx,
|
||||
)),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum LayoutMode {
|
||||
Single,
|
||||
Compact,
|
||||
}
|
||||
|
||||
fn render_layout_card(
|
||||
title: &'static str,
|
||||
detail: &'static str,
|
||||
selected: bool,
|
||||
mode: LayoutMode,
|
||||
cx: &mut Context<ElyShell>,
|
||||
) -> AnyElement {
|
||||
let id = SharedString::from(match mode {
|
||||
LayoutMode::Single => "layout-single",
|
||||
LayoutMode::Compact => "layout-compact",
|
||||
});
|
||||
|
||||
div()
|
||||
.id(id)
|
||||
.p(px(14.0))
|
||||
.rounded(px(14.0))
|
||||
.bg(rgba(LAYOUT_CARD_BG))
|
||||
.when(selected, |el| el.border_2().border_color(rgb(colors::ACCENT)))
|
||||
.when(!selected, |el| el.border_1().border_color(rgba(colors::STROKE)))
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap(px(10.0))
|
||||
.cursor_pointer()
|
||||
.hover(|style| style.opacity(0.94))
|
||||
.active(|style| style.opacity(0.85))
|
||||
.on_click(cx.listener(move |shell, _, _, cx| {
|
||||
let width = match mode {
|
||||
LayoutMode::Single => DEFAULT_SIDEBAR_WIDTH_PX,
|
||||
LayoutMode::Compact => COLLAPSED_SIDEBAR_WIDTH_PX,
|
||||
};
|
||||
shell.set_active_sidebar_width(width, cx);
|
||||
}))
|
||||
.child(render_layout_preview(mode))
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap(px(2.0))
|
||||
.child(
|
||||
div()
|
||||
.text_size(px(12.5))
|
||||
.font_weight(FontWeight(500.0))
|
||||
.text_color(rgb(colors::INK))
|
||||
.child(title),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.text_size(px(11.0))
|
||||
.text_color(rgb(colors::INK_4))
|
||||
.child(detail),
|
||||
),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn render_layout_preview(mode: LayoutMode) -> AnyElement {
|
||||
let sidebar_width = match mode {
|
||||
LayoutMode::Single => 56.0,
|
||||
LayoutMode::Compact => 18.0,
|
||||
};
|
||||
|
||||
div()
|
||||
.h(px(96.0))
|
||||
.rounded(px(8.0))
|
||||
.bg(rgb(0xffffff))
|
||||
.relative()
|
||||
.child(
|
||||
div()
|
||||
.absolute()
|
||||
.left(px(6.0))
|
||||
.top(px(6.0))
|
||||
.bottom(px(6.0))
|
||||
.w(px(sidebar_width))
|
||||
.rounded(px(5.0))
|
||||
.bg(rgba(LAYOUT_PANEL_BG)),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.absolute()
|
||||
.left(px(sidebar_width + 12.0))
|
||||
.top(px(6.0))
|
||||
.right(px(6.0))
|
||||
.bottom(px(6.0))
|
||||
.rounded(px(5.0))
|
||||
.bg(rgba(LAYOUT_CANVAS_BG)),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
const LAYOUT_CARD_BG: u32 = 0xffffffd9;
|
||||
const LAYOUT_PANEL_BG: u32 = 0x281e1414;
|
||||
const LAYOUT_CANVAS_BG: u32 = 0x281e140a;
|
||||
@@ -1,4 +1,5 @@
|
||||
pub(crate) mod appearance_form;
|
||||
pub(crate) mod appearance_layout_cards;
|
||||
pub(crate) mod brand_glyph;
|
||||
pub(crate) mod command_footer;
|
||||
pub(crate) mod command_overlay;
|
||||
|
||||
@@ -112,6 +112,20 @@ impl ElyShell {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_active_sidebar_width(&mut self, width_px: u16, cx: &mut Context<Self>) {
|
||||
let ShellState::Ready(core) = &mut self.state else {
|
||||
return;
|
||||
};
|
||||
let active_space_id = match core.snapshot() {
|
||||
Ok(snapshot) => snapshot.active_space_id,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
if core.set_space_sidebar_width(&active_space_id, width_px).is_ok() {
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
fn render_compact_space_button(
|
||||
&mut self,
|
||||
index: usize,
|
||||
|
||||
Reference in New Issue
Block a user