Add tab group color command

This commit is contained in:
2026-05-08 11:13:39 -04:00
parent 5588237a1f
commit 0e01395a5d
5 changed files with 105 additions and 2 deletions
+17
View File
@@ -112,6 +112,14 @@ pub(crate) fn rename_tab_group_name(command: &str) -> Option<&str> {
)
}
pub(crate) fn tab_group_color_hex(command: &str) -> Option<u32> {
let value = command_argument(
command,
&["set-tab-group-color ", "set tab group color ", "tab-group-color ", "tab group color "],
)?;
parse_color_hex(value)
}
pub(crate) fn split_group_name(command: &str) -> Option<&str> {
command_argument(
command,
@@ -142,6 +150,15 @@ fn command_argument<'a>(command: &'a str, prefixes: &[&str]) -> Option<&'a str>
None
}
fn parse_color_hex(value: &str) -> Option<u32> {
let value = value.trim().strip_prefix('#').unwrap_or(value.trim());
if value.len() != 6 || !value.as_bytes().iter().all(u8::is_ascii_hexdigit) {
return None;
}
u32::from_str_radix(value, 16).ok()
}
pub(crate) fn space_icon(name: &str) -> String {
name.chars().next().map_or_else(String::new, |value| value.to_string())
}
@@ -11,8 +11,8 @@ use crate::{
move_tab_space_name, new_private_profile_name, new_profile_name, new_space_name, note_body,
notes_url, plugin_detail_url, plugins_url, reading_list_url, reading_progress_percent,
rename_tab_group_name, search_url, settings_page_url, settings_url, shortcut_settings_url,
space_icon, split_group_name, switch_profile_name, sync_status_url, tab_group_name,
tab_note_body, task_manager_url,
space_icon, split_group_name, switch_profile_name, sync_status_url, tab_group_color_hex,
tab_group_name, tab_note_body, task_manager_url,
},
};
@@ -149,6 +149,9 @@ impl BrowserCore {
if let Some(name) = rename_tab_group_name(command) {
return Ok(self.rename_active_tab_group(name)?.is_some());
}
if let Some(color_hex) = tab_group_color_hex(command) {
return Ok(self.set_active_tab_group_color(color_hex)?.is_some());
}
if let Some(body) = tab_note_body(command) {
self.save_active_tab_note(body)?;
return Ok(true);
@@ -100,6 +100,24 @@ impl BrowserCore {
group.rename(name).map_err(CoreError::from)
}
pub fn set_active_tab_group_color(&mut self, color_hex: u32) -> Result<Option<()>, CoreError> {
let Some(group_id) = self.active_tab_group_id()? else {
return Ok(None);
};
self.set_tab_group_color(&group_id, color_hex)?;
Ok(Some(()))
}
pub fn set_tab_group_color(
&mut self,
group_id: &TabGroupId,
color_hex: u32,
) -> Result<(), CoreError> {
let group = self.tab_group_mut(group_id)?;
group.set_color_hex(color_hex);
Ok(())
}
pub fn discard_active_tab_group(&mut self) -> Result<Option<usize>, CoreError> {
let Some(group_id) = self.active_tab_group_id()? else {
return Ok(None);
@@ -39,6 +39,56 @@ fn rename_tab_group_command_preserves_query_without_active_group() -> Result<(),
Ok(())
}
#[test]
fn tab_group_color_command_updates_active_group_color() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
core.group_active_tab("Docs")?;
core.set_command_query(">tab-group-color #9FC9A2");
let intent = core.submit_command()?;
let snapshot = core.snapshot()?;
let group = snapshot.tab_groups.first().ok_or("missing tab group")?;
assert_eq!(intent, Some(CommandIntent::Command("tab-group-color #9FC9A2".to_string())));
assert_eq!(snapshot.command_query, "");
assert_eq!(group.color_hex(), 0x9fc9a2);
Ok(())
}
#[test]
fn tab_group_color_command_preserves_query_without_active_group() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
core.set_command_query(">tab-group-color #9FC9A2");
let intent = core.submit_command()?;
let snapshot = core.snapshot()?;
assert_eq!(intent, Some(CommandIntent::Command("tab-group-color #9FC9A2".to_string())));
assert_eq!(snapshot.command_query, ">tab-group-color #9FC9A2");
assert!(snapshot.tab_groups.is_empty());
Ok(())
}
#[test]
fn tab_group_color_command_preserves_query_for_invalid_hex() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let group_id = core.group_active_tab("Docs")?;
core.set_command_query(">tab-group-color orange");
let intent = core.submit_command()?;
let snapshot = core.snapshot()?;
let group = snapshot
.tab_groups
.iter()
.find(|group| group.id() == &group_id)
.ok_or("missing tab group")?;
assert_eq!(intent, Some(CommandIntent::Command("tab-group-color orange".to_string())));
assert_eq!(snapshot.command_query, ">tab-group-color orange");
assert_eq!(group.color_hex(), 0xf54e00);
Ok(())
}
fn tab_group_id<'a>(
snapshot: &'a ely_browser_core::BrowserSnapshot,
tab_id: &ely_domain::TabId,
+15
View File
@@ -103,6 +103,21 @@ Group rename updates the active group row in place:
└──────────────────────────────┴───────────────────────────────────────────────┘
```
Group color updates the active group accent:
```text
┌──────────────────────────────────────────────────────────────────────────────┐
│ ELY Browser [ >tab-group-color #9FC9A2.................. ] [pin] [*] [+] │
├──────────────────────────────┬───────────────────────────────────────────────┤
│ Tabs │ example.com │
│ [folder] Docs │ https://example.com/b │
│ 2 tabs - Expanded │ │
│ color #9FC9A2 │ Group Docs │
│ example.com │ │
│ example.com │ │
└──────────────────────────────┴───────────────────────────────────────────────┘
```
Group sleep applies the sleeping state to every tab in the active group:
```text