audit command palette

This commit is contained in:
2026-11-08 12:48:07 +07:00
parent abb56567e4
commit 4b7fce8edc
4 changed files with 31 additions and 16 deletions
+22 -3
View File
@@ -10,6 +10,7 @@ use gpui::{
ScrollHandle, SharedString, StatefulInteractiveElement as _, Styled as _, Subscription, Window, ScrollHandle, SharedString, StatefulInteractiveElement as _, Styled as _, Subscription, Window,
actions, canvas, div, px, relative, actions, canvas, div, px, relative,
}; };
use gpui_native_icons::{IconRole, icon};
use gpui_native_theme::{ActiveTheme as _, Size}; use gpui_native_theme::{ActiveTheme as _, Size};
use crate::common::{h_flex, v_flex}; use crate::common::{h_flex, v_flex};
@@ -48,18 +49,27 @@ pub struct Command {
pub label: SharedString, pub label: SharedString,
/// Gray text on the row's right edge, e.g. the keybinding. /// Gray text on the row's right edge, e.g. the keybinding.
pub hint: Option<SharedString>, pub hint: Option<SharedString>,
/// Leading glyph shown before the label.
pub icon: Option<IconRole>,
} }
impl Command { impl Command {
/// Creates a command without a hint. /// Creates a command without a hint or icon.
pub fn new(id: impl Into<SharedString>, label: impl Into<SharedString>) -> Self { pub fn new(id: impl Into<SharedString>, label: impl Into<SharedString>) -> Self {
Self { Self {
id: id.into(), id: id.into(),
label: label.into(), label: label.into(),
hint: None, hint: None,
icon: None,
} }
} }
/// Shows an icon before the label.
pub fn icon(mut self, role: IconRole) -> Self {
self.icon = Some(role);
self
}
/// Sets the row's right-edge hint. /// Sets the row's right-edge hint.
pub fn hint(mut self, hint: impl Into<SharedString>) -> Self { pub fn hint(mut self, hint: impl Into<SharedString>) -> Self {
self.hint = Some(hint.into()); self.hint = Some(hint.into());
@@ -295,15 +305,21 @@ impl Render for CommandPaletteState {
return div().into_any_element(); return div().into_any_element();
} }
let (colors, radius, metrics, shadows) = { let (colors, radius, metrics, panel_border, shadows) = {
let theme = cx.theme(); let theme = cx.theme();
( (
theme.colors, theme.colors,
theme.radius, theme.radius,
theme.sizes.resolve(Size::default()), theme.sizes.resolve(Size::default()),
if theme.borders.overlays {
theme.colors.border
} else {
theme.colors.surface
},
theme.elevations.dialog.shadows(), theme.elevations.dialog.shadows(),
) )
}; };
let id = self.id.clone(); let id = self.id.clone();
let state = cx.entity(); let state = cx.entity();
@@ -345,6 +361,9 @@ impl Render for CommandPaletteState {
state.update(cx, |state, cx| state.choose_row(row_ix, window, cx)); state.update(cx, |state, cx| state.choose_row(row_ix, window, cx));
} }
}) })
.when_some(command.icon, |row, role| {
row.child(icon(role).size(metrics.icon_size).color(colors.foreground))
})
.child( .child(
div() div()
.flex_1() .flex_1()
@@ -407,7 +426,7 @@ impl Render for CommandPaletteState {
.text_color(colors.foreground) .text_color(colors.foreground)
.rounded(radius.overlay) .rounded(radius.overlay)
.border_1() .border_1()
.border_color(colors.border) .border_color(panel_border)
.shadow(shadows) .shadow(shadows)
.overflow_hidden() .overflow_hidden()
.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation()) .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
-2
View File
@@ -419,8 +419,6 @@ impl SizeTable {
}; };
let metrics = |f: &ClassFactors| { let metrics = |f: &ClassFactors| {
// Standard controls carry 16px glyphs on every platform, fixed
// against the root font the way the platforms fix them.
let icon_size = if f.floor_icon { let icon_size = if f.floor_icon {
(rem_size * f.icon).max(px(16.)) (rem_size * f.icon).max(px(16.))
} else { } else {
+5 -9
View File
@@ -14,10 +14,6 @@ is the first downstream consumer; its screens drive the order.
Platform metric adoption continues one component at a time; each stop goes Platform metric adoption continues one component at a time; each stop goes
through the review gate and a gallery pass. through the review gate and a gallery pass.
- [ ] **Combobox platform chrome** — popup border behind
`Theme::borders.overlays`; the trigger follows the input stop's field
treatment.
- [ ] **Command palette platform chrome** — overlay border gate.
- [ ] **Switch platform chrome** — stated track and knob dims - [ ] **Switch platform chrome** — stated track and knob dims
(`switch_height` / `switch_width` / `switch_knob`, inset and travel (`switch_height` / `switch_width` / `switch_knob`, inset and travel
derived); borderless knob. derived); borderless knob.
@@ -143,11 +139,10 @@ Gaps surfaced by the signed comparison; ordered by signed's usage.
(`.w(...)`) set the width; the empty field keeps its placeholder while (`.w(...)`) set the width; the empty field keeps its placeholder while
focused (`Input::placeholder_when_focused`) and clicking into it opens focused (`Input::placeholder_when_focused`) and clicking into it opens
the options right away, with no keystroke needed the options right away, with no keystroke needed
- [x] Combobox platform chrome — the popup border behind - [x] Command palette platform chrome — the panel border behind
`Theme::borders.overlays` (and dark mode), taking the surface color `Theme::borders.overlays` (and dark mode), taking the surface color
where the platform paints none; the trigger is a plain `Input`, so it where the platform paints none; it rides the dialog elevation, so dark
already carries the full field treatment, and the chevron recenters on mode's no-shadow rule applies to it too
the field's full height, border included
- [x] Button, Checkbox, Switch, Radio + RadioGroup, Toggle, Link, Slider, - [x] Button, Checkbox, Switch, Radio + RadioGroup, Toggle, Link, Slider,
Progress, Avatar (image + seeded pixel-art fallback) Progress, Avatar (image + seeded pixel-art fallback)
- [x] Spinner — painted ring + rotating-icon variant, indeterminate and - [x] Spinner — painted ring + rotating-icon variant, indeterminate and
@@ -166,7 +161,8 @@ Gaps surfaced by the signed comparison; ordered by signed's usage.
screen-reader label screen-reader label
- [x] Combobox — type-to-filter picker with a caller-owned matcher, create / - [x] Combobox — type-to-filter picker with a caller-owned matcher, create /
keep / revert blur modes keep / revert blur modes
- [x] Command palette — filtered actions; the matcher stays caller-owned - [x] Command palette — filtered actions; the matcher stays caller-owned,
and commands may carry a leading icon
- [x] Scrollbar — overlay thumbs for gpui's `list` and `uniform_list`, - [x] Scrollbar — overlay thumbs for gpui's `list` and `uniform_list`,
platform autohide with a `visibility` override platform autohide with a `visibility` override
- [x] Clipboard button — copies a value, confirms with a brief check mark - [x] Clipboard button — copies a value, confirms with a brief check mark
+4 -2
View File
@@ -205,8 +205,10 @@ fn gallery_commands() -> Vec<Command> {
Command::new("open-settings", "Open Settings").hint("Cmd+,"), Command::new("open-settings", "Open Settings").hint("Cmd+,"),
Command::new("toggle-theme", "Toggle Theme").hint("Shift+Cmd+T"), Command::new("toggle-theme", "Toggle Theme").hint("Shift+Cmd+T"),
Command::new("save-all", "Save All").hint("Cmd+Alt+S"), Command::new("save-all", "Save All").hint("Cmd+Alt+S"),
Command::new("close-tab", "Close Tab").hint("Cmd+W"), Command::new("close-tab", "Close Tab")
Command::new("reload-window", "Reload Window"), .hint("Cmd+W")
.icon(IconRole::Close),
Command::new("reload-window", "Reload Window").icon(IconRole::Loader),
] ]
} }