feat(spaces): make the Space accent real end to end
This commit is contained in:
@@ -97,6 +97,7 @@ fn render_picker_pill(
|
||||
) -> AnyElement {
|
||||
let space_name = active_space.map(|space| space.name().to_string()).unwrap_or_default();
|
||||
let space_glyph = active_space.map(|space| space.icon().to_string()).unwrap_or_default();
|
||||
let space_accent = active_space.map(ely_domain::Space::accent_hex);
|
||||
let chevron = if picker_open { IconName::ChevronUp } else { IconName::ChevronDown };
|
||||
let bg = if picker_open { picker_bg_hover() } else { picker_bg() };
|
||||
|
||||
@@ -118,7 +119,7 @@ fn render_picker_pill(
|
||||
.on_click(cx.listener(|shell, _, _, cx| {
|
||||
shell.toggle_workspace_picker(cx);
|
||||
}))
|
||||
.child(render_workspace_glyph(space_glyph))
|
||||
.child(render_workspace_glyph(space_glyph, space_accent))
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
@@ -260,7 +261,7 @@ fn render_disclosure_row(
|
||||
.on_click(cx.listener(move |shell, _, window, cx| {
|
||||
shell.select_space_from_picker(&space_id, window, cx);
|
||||
}))
|
||||
.child(render_workspace_glyph(space.icon().to_string()))
|
||||
.child(render_workspace_glyph(space.icon().to_string(), Some(space.accent_hex())))
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
@@ -301,15 +302,17 @@ fn render_disclosure_footer(cx: &mut Context<ElyShell>) -> AnyElement {
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn render_workspace_glyph(emoji: String) -> AnyElement {
|
||||
div()
|
||||
.size(px(18.0))
|
||||
.rounded(px(5.0))
|
||||
.bg(linear_gradient(
|
||||
fn render_workspace_glyph(emoji: String, accent_hex: Option<u32>) -> AnyElement {
|
||||
let glyph = div().size(px(18.0)).rounded(px(5.0));
|
||||
let glyph = match accent_hex {
|
||||
Some(accent) => glyph.bg(rgb(accent)),
|
||||
None => glyph.bg(linear_gradient(
|
||||
135.0,
|
||||
linear_color_stop(hsla(341.0 / 360.0, 0.78, 0.67, 1.0), 0.0),
|
||||
linear_color_stop(hsla(15.0 / 360.0, 0.55, 0.53, 1.0), 1.0),
|
||||
))
|
||||
)),
|
||||
};
|
||||
glyph
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
|
||||
@@ -123,6 +123,14 @@ pub(crate) fn tab_group_color_hex(command: &str) -> Option<u32> {
|
||||
parse_color_hex(value)
|
||||
}
|
||||
|
||||
pub(crate) fn space_accent_hex(command: &str) -> Option<u32> {
|
||||
let value = command_argument(
|
||||
command,
|
||||
&["set-space-accent ", "set space accent ", "space-accent ", "space accent "],
|
||||
)?;
|
||||
parse_color_hex(value)
|
||||
}
|
||||
|
||||
pub(crate) fn split_group_name(command: &str) -> Option<&str> {
|
||||
command_argument(
|
||||
command,
|
||||
|
||||
@@ -262,6 +262,17 @@ impl BrowserCore {
|
||||
self.set_space_archive_policy(&active_space_id, archive_policy)
|
||||
}
|
||||
|
||||
pub fn set_active_space_accent(&mut self, accent_hex: u32) -> Result<(), CoreError> {
|
||||
let active_space_id = self.active_space_id.clone();
|
||||
let space = self
|
||||
.spaces
|
||||
.iter_mut()
|
||||
.find(|space| space.id() == &active_space_id)
|
||||
.ok_or_else(|| CoreError::SpaceNotFound { id: active_space_id.clone() })?;
|
||||
space.set_accent_hex(accent_hex);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_space_archive_policy(
|
||||
&mut self,
|
||||
space_id: &SpaceId,
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::{
|
||||
move_tab_space_name, new_private_profile_name, new_profile_name, new_space_name, note_body,
|
||||
notes_url, plugin_detail_url, plugin_settings_url, plugins_url, reading_list_url,
|
||||
reading_progress_percent, rename_tab_group_name, search_url, settings_page_url,
|
||||
settings_url, shortcut_settings_url, site_compatibility_url, space_icon,
|
||||
settings_url, shortcut_settings_url, site_compatibility_url, space_accent_hex, space_icon,
|
||||
space_settings_url, split_group_name, switch_profile_name, sync_status_url,
|
||||
tab_group_color_hex, tab_group_name, tab_note_body, task_manager_url,
|
||||
},
|
||||
@@ -111,7 +111,11 @@ impl BrowserCore {
|
||||
fn submit_named_command(&mut self, command: &str) -> Result<bool, CoreError> {
|
||||
let command = command.trim();
|
||||
if let Some(name) = new_space_name(command) {
|
||||
self.create_space(name.to_string(), space_icon(name), 0xf54e00)?;
|
||||
self.create_space(name.to_string(), space_icon(name), self.next_space_accent())?;
|
||||
return Ok(true);
|
||||
}
|
||||
if let Some(accent_hex) = space_accent_hex(command) {
|
||||
self.set_active_space_accent(accent_hex)?;
|
||||
return Ok(true);
|
||||
}
|
||||
if let Some(name) = new_profile_name(command) {
|
||||
|
||||
@@ -59,6 +59,15 @@ impl TrashedSpace {
|
||||
}
|
||||
|
||||
impl BrowserCore {
|
||||
/// Rotate new spaces through distinct accents so workspace identity
|
||||
/// reads at a glance; `>space-accent` overrides per space.
|
||||
#[must_use]
|
||||
pub fn next_space_accent(&self) -> u32 {
|
||||
const SPACE_ACCENT_PALETTE: &[u32] =
|
||||
&[0xf54e00, 0x0f7b6c, 0x2f5fe0, 0x8a4bd8, 0xb26b00, 0xc23a63];
|
||||
SPACE_ACCENT_PALETTE[self.spaces.len() % SPACE_ACCENT_PALETTE.len()]
|
||||
}
|
||||
|
||||
pub fn create_space(
|
||||
&mut self,
|
||||
name: impl Into<String>,
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
use std::error::Error;
|
||||
|
||||
use ely_browser_core::{BrowserCore, InitialBrowserConfig};
|
||||
use ely_domain::CommandIntent;
|
||||
|
||||
#[test]
|
||||
fn space_accent_command_updates_the_active_space() -> Result<(), Box<dyn Error>> {
|
||||
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||
|
||||
core.set_command_query(">space-accent #123ABC");
|
||||
let intent = core.submit_command()?;
|
||||
let snapshot = core.snapshot()?;
|
||||
let active_space = snapshot
|
||||
.spaces
|
||||
.iter()
|
||||
.find(|space| space.id() == &snapshot.active_space_id)
|
||||
.ok_or("missing active space")?;
|
||||
|
||||
assert_eq!(intent, Some(CommandIntent::Command("space-accent #123ABC".to_string())));
|
||||
assert_eq!(snapshot.command_query, "");
|
||||
assert_eq!(active_space.accent_hex(), 0x123abc);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn space_accent_command_preserves_query_for_invalid_hex() -> Result<(), Box<dyn Error>> {
|
||||
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||
let original_accent = core.snapshot()?.spaces[0].accent_hex();
|
||||
|
||||
core.set_command_query(">space-accent #12");
|
||||
core.submit_command()?;
|
||||
let snapshot = core.snapshot()?;
|
||||
|
||||
assert_eq!(snapshot.command_query, ">space-accent #12");
|
||||
assert_eq!(snapshot.spaces[0].accent_hex(), original_accent);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_spaces_rotate_through_the_accent_palette() -> Result<(), Box<dyn Error>> {
|
||||
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||
|
||||
core.set_command_query(">new-space Research");
|
||||
core.submit_command()?;
|
||||
core.set_command_query(">new-space Notes");
|
||||
core.submit_command()?;
|
||||
|
||||
let snapshot = core.snapshot()?;
|
||||
let accents: Vec<u32> = snapshot.spaces.iter().map(ely_domain::Space::accent_hex).collect();
|
||||
assert_eq!(accents.len(), 3);
|
||||
assert_ne!(accents[1], accents[2], "consecutive spaces must not share one accent");
|
||||
Ok(())
|
||||
}
|
||||
@@ -80,6 +80,11 @@ impl Space {
|
||||
self.record_update();
|
||||
}
|
||||
|
||||
pub fn set_accent_hex(&mut self, accent_hex: u32) {
|
||||
self.accent_hex = accent_hex;
|
||||
self.record_update();
|
||||
}
|
||||
|
||||
pub fn set_presentation(
|
||||
&mut self,
|
||||
name: impl Into<String>,
|
||||
|
||||
Reference in New Issue
Block a user