assets/icons/star.svg 🔗
@@ -1 +1,3 @@
Danilo Leal created
Just polishing up a bit the Rules Library design. I think the most
confusing part here was the icon that was being used to tag a rule as
default; I've heard feedback more than once saying that was confusing,
so I'm now switching to a rather standard star icon, which I'd assume is
well-understood as a "favoriting" affordance.
Release Notes:
- N/A
assets/icons/star.svg | 0
assets/icons/star_filled.svg | 2
crates/rules_library/src/rules_library.rs | 381 ++++++++++++------------
3 files changed, 184 insertions(+), 199 deletions(-)
@@ -1 +1,3 @@
@@ -1 +1,3 @@
-<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.22303 0.665992C7.32551 0.419604 7.67454 0.419604 7.77702 0.665992L9.41343 4.60039C9.45663 4.70426 9.55432 4.77523 9.66645 4.78422L13.914 5.12475C14.18 5.14607 14.2878 5.47802 14.0852 5.65162L10.849 8.42374C10.7636 8.49692 10.7263 8.61176 10.7524 8.72118L11.7411 12.866C11.803 13.1256 11.5206 13.3308 11.2929 13.1917L7.6564 10.9705C7.5604 10.9119 7.43965 10.9119 7.34365 10.9705L3.70718 13.1917C3.47945 13.3308 3.19708 13.1256 3.25899 12.866L4.24769 8.72118C4.2738 8.61176 4.23648 8.49692 4.15105 8.42374L0.914889 5.65162C0.712228 5.47802 0.820086 5.14607 1.08608 5.12475L5.3336 4.78422C5.44573 4.77523 5.54342 4.70426 5.58662 4.60039L7.22303 0.665992Z" fill="currentColor"></path></svg>
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
@@ -261,6 +261,7 @@ impl PickerDelegate for RulePickerDelegate {
let rule = self.matches.get(ix)?;
let default = rule.default;
let prompt_id = rule.id;
+
let element = ListItem::new(ix)
.inset(true)
.spacing(ListItemSpacing::Sparse)
@@ -272,9 +273,10 @@ impl PickerDelegate for RulePickerDelegate {
.child(Label::new(rule.title.clone().unwrap_or("Untitled".into()))),
)
.end_slot::<IconButton>(default.then(|| {
- IconButton::new("toggle-default-rule", IconName::SparkleFilled)
+ IconButton::new("toggle-default-rule", IconName::StarFilled)
.toggle_state(true)
.icon_color(Color::Accent)
+ .icon_size(IconSize::Small)
.shape(IconButtonShape::Square)
.tooltip(Tooltip::text("Remove from Default Rules"))
.on_click(cx.listener(move |_, _, _, cx| {
@@ -283,7 +285,7 @@ impl PickerDelegate for RulePickerDelegate {
}))
.end_hover_slot(
h_flex()
- .gap_2()
+ .gap_1()
.child(if prompt_id.is_built_in() {
div()
.id("built-in-rule")
@@ -299,8 +301,9 @@ impl PickerDelegate for RulePickerDelegate {
})
.into_any()
} else {
- IconButton::new("delete-rule", IconName::Trash)
+ IconButton::new("delete-rule", IconName::TrashAlt)
.icon_color(Color::Muted)
+ .icon_size(IconSize::Small)
.shape(IconButtonShape::Square)
.tooltip(Tooltip::text("Delete Rule"))
.on_click(cx.listener(move |_, _, _, cx| {
@@ -309,16 +312,27 @@ impl PickerDelegate for RulePickerDelegate {
.into_any_element()
})
.child(
- IconButton::new("toggle-default-rule", IconName::Sparkle)
+ IconButton::new("toggle-default-rule", IconName::Star)
.toggle_state(default)
- .selected_icon(IconName::SparkleFilled)
+ .selected_icon(IconName::StarFilled)
.icon_color(if default { Color::Accent } else { Color::Muted })
+ .icon_size(IconSize::Small)
.shape(IconButtonShape::Square)
- .tooltip(Tooltip::text(if default {
- "Remove from Default Rules"
- } else {
- "Add to Default Rules"
- }))
+ .map(|this| {
+ if default {
+ this.tooltip(Tooltip::text("Remove from Default Rules"))
+ } else {
+ this.tooltip(move |window, cx| {
+ Tooltip::with_meta(
+ "Add to Default Rules",
+ None,
+ "Always included in every thread.",
+ window,
+ cx,
+ )
+ })
+ }
+ })
.on_click(cx.listener(move |_, _, _, cx| {
cx.emit(RulePickerEvent::ToggledDefault { prompt_id })
})),
@@ -1008,216 +1022,180 @@ impl RulesLibrary {
.size_full()
.relative()
.overflow_hidden()
- .pl(DynamicSpacing::Base16.rems(cx))
- .pt(DynamicSpacing::Base08.rems(cx))
.on_click(cx.listener(move |_, _, window, _| {
window.focus(&focus_handle);
}))
.child(
h_flex()
.group("active-editor-header")
- .pr(DynamicSpacing::Base16.rems(cx))
- .pt(DynamicSpacing::Base02.rems(cx))
- .pb(DynamicSpacing::Base08.rems(cx))
+ .pt_2()
+ .px_2p5()
+ .gap_2()
.justify_between()
.child(
- h_flex().gap_1().child(
- div()
- .max_w_80()
- .on_action(cx.listener(Self::move_down_from_title))
- .border_1()
- .border_color(transparent_black())
- .rounded_sm()
- .group_hover("active-editor-header", |this| {
- this.border_color(
- cx.theme().colors().border_variant,
- )
- })
- .child(EditorElement::new(
- &rule_editor.title_editor,
- EditorStyle {
- background: cx.theme().system().transparent,
- local_player: cx.theme().players().local(),
- text: TextStyle {
- color: cx
- .theme()
- .colors()
- .editor_foreground,
- font_family: settings
- .ui_font
- .family
- .clone(),
- font_features: settings
- .ui_font
- .features
- .clone(),
- font_size: HeadlineSize::Large
- .rems()
- .into(),
- font_weight: settings.ui_font.weight,
- line_height: relative(
- settings.buffer_line_height.value(),
- ),
- ..Default::default()
- },
- scrollbar_width: Pixels::ZERO,
- syntax: cx.theme().syntax().clone(),
- status: cx.theme().status().clone(),
- inlay_hints_style:
- editor::make_inlay_hints_style(cx),
- inline_completion_styles:
- editor::make_suggestion_styles(cx),
- ..EditorStyle::default()
+ div()
+ .w_full()
+ .on_action(cx.listener(Self::move_down_from_title))
+ .border_1()
+ .border_color(transparent_black())
+ .rounded_sm()
+ .group_hover("active-editor-header", |this| {
+ this.border_color(cx.theme().colors().border_variant)
+ })
+ .child(EditorElement::new(
+ &rule_editor.title_editor,
+ EditorStyle {
+ background: cx.theme().system().transparent,
+ local_player: cx.theme().players().local(),
+ text: TextStyle {
+ color: cx.theme().colors().editor_foreground,
+ font_family: settings.ui_font.family.clone(),
+ font_features: settings
+ .ui_font
+ .features
+ .clone(),
+ font_size: HeadlineSize::Large.rems().into(),
+ font_weight: settings.ui_font.weight,
+ line_height: relative(
+ settings.buffer_line_height.value(),
+ ),
+ ..Default::default()
},
- )),
- ),
+ scrollbar_width: Pixels::ZERO,
+ syntax: cx.theme().syntax().clone(),
+ status: cx.theme().status().clone(),
+ inlay_hints_style: editor::make_inlay_hints_style(
+ cx,
+ ),
+ inline_completion_styles:
+ editor::make_suggestion_styles(cx),
+ ..EditorStyle::default()
+ },
+ )),
)
.child(
h_flex()
.h_full()
+ .flex_shrink_0()
+ .gap(DynamicSpacing::Base04.rems(cx))
+ .children(rule_editor.token_count.map(|token_count| {
+ let token_count: SharedString =
+ token_count.to_string().into();
+ let label_token_count: SharedString =
+ token_count.to_string().into();
+
+ div()
+ .id("token_count")
+ .mr_1()
+ .flex_shrink_0()
+ .tooltip(move |window, cx| {
+ Tooltip::with_meta(
+ "Token Estimation",
+ None,
+ format!(
+ "Model: {}",
+ model
+ .as_ref()
+ .map(|model| model.name().0)
+ .unwrap_or_default()
+ ),
+ window,
+ cx,
+ )
+ })
+ .child(
+ Label::new(format!(
+ "{} tokens",
+ label_token_count.clone()
+ ))
+ .color(Color::Muted),
+ )
+ }))
+ .child(if prompt_id.is_built_in() {
+ div()
+ .id("built-in-rule")
+ .child(
+ Icon::new(IconName::FileLock)
+ .color(Color::Muted),
+ )
+ .tooltip(move |window, cx| {
+ Tooltip::with_meta(
+ "Built-in rule",
+ None,
+ BUILT_IN_TOOLTIP_TEXT,
+ window,
+ cx,
+ )
+ })
+ .into_any()
+ } else {
+ IconButton::new("delete-rule", IconName::TrashAlt)
+ .icon_size(IconSize::Small)
+ .tooltip(move |window, cx| {
+ Tooltip::for_action(
+ "Delete Rule",
+ &DeleteRule,
+ window,
+ cx,
+ )
+ })
+ .on_click(|_, window, cx| {
+ window
+ .dispatch_action(Box::new(DeleteRule), cx);
+ })
+ .into_any_element()
+ })
.child(
- h_flex()
- .h_full()
- .gap(DynamicSpacing::Base16.rems(cx))
- .child(div()),
+ IconButton::new("duplicate-rule", IconName::BookCopy)
+ .icon_size(IconSize::Small)
+ .tooltip(move |window, cx| {
+ Tooltip::for_action(
+ "Duplicate Rule",
+ &DuplicateRule,
+ window,
+ cx,
+ )
+ })
+ .on_click(|_, window, cx| {
+ window.dispatch_action(
+ Box::new(DuplicateRule),
+ cx,
+ );
+ }),
)
.child(
- h_flex()
- .h_full()
- .gap(DynamicSpacing::Base16.rems(cx))
- .children(rule_editor.token_count.map(
- |token_count| {
- let token_count: SharedString =
- token_count.to_string().into();
- let label_token_count: SharedString =
- token_count.to_string().into();
-
- h_flex()
- .id("token_count")
- .tooltip(move |window, cx| {
- let token_count =
- token_count.clone();
-
- Tooltip::with_meta(
- format!(
- "{} tokens",
- token_count.clone()
- ),
- None,
- format!(
- "Model: {}",
- model
- .as_ref()
- .map(|model| model
- .name()
- .0)
- .unwrap_or_default()
- ),
- window,
- cx,
- )
- })
- .child(
- Label::new(format!(
- "{} tokens",
- label_token_count.clone()
- ))
- .color(Color::Muted),
- )
- },
- ))
- .child(if prompt_id.is_built_in() {
- div()
- .id("built-in-rule")
- .child(
- Icon::new(IconName::FileLock)
- .color(Color::Muted),
- )
- .tooltip(move |window, cx| {
+ IconButton::new("toggle-default-rule", IconName::Star)
+ .icon_size(IconSize::Small)
+ .toggle_state(rule_metadata.default)
+ .selected_icon(IconName::StarFilled)
+ .icon_color(if rule_metadata.default {
+ Color::Accent
+ } else {
+ Color::Muted
+ })
+ .map(|this| {
+ if rule_metadata.default {
+ this.tooltip(Tooltip::text(
+ "Remove from Default Rules",
+ ))
+ } else {
+ this.tooltip(move |window, cx| {
Tooltip::with_meta(
- "Built-in rule",
+ "Add to Default Rules",
None,
- BUILT_IN_TOOLTIP_TEXT,
+ "Always included in every thread.",
window,
cx,
)
})
- .into_any()
- } else {
- IconButton::new("delete-rule", IconName::Trash)
- .size(ButtonSize::Large)
- .style(ButtonStyle::Transparent)
- .shape(IconButtonShape::Square)
- .size(ButtonSize::Large)
- .tooltip(move |window, cx| {
- Tooltip::for_action(
- "Delete Rule",
- &DeleteRule,
- window,
- cx,
- )
- })
- .on_click(|_, window, cx| {
- window.dispatch_action(
- Box::new(DeleteRule),
- cx,
- );
- })
- .into_any_element()
+ }
})
- .child(
- IconButton::new(
- "duplicate-rule",
- IconName::BookCopy,
- )
- .size(ButtonSize::Large)
- .style(ButtonStyle::Transparent)
- .shape(IconButtonShape::Square)
- .size(ButtonSize::Large)
- .tooltip(move |window, cx| {
- Tooltip::for_action(
- "Duplicate Rule",
- &DuplicateRule,
- window,
- cx,
- )
- })
- .on_click(|_, window, cx| {
- window.dispatch_action(
- Box::new(DuplicateRule),
- cx,
- );
- }),
- )
- .child(
- IconButton::new(
- "toggle-default-rule",
- IconName::Sparkle,
- )
- .style(ButtonStyle::Transparent)
- .toggle_state(rule_metadata.default)
- .selected_icon(IconName::SparkleFilled)
- .icon_color(if rule_metadata.default {
- Color::Accent
- } else {
- Color::Muted
- })
- .shape(IconButtonShape::Square)
- .size(ButtonSize::Large)
- .tooltip(Tooltip::text(
- if rule_metadata.default {
- "Remove from Default Rules"
- } else {
- "Add to Default Rules"
- },
- ))
- .on_click(|_, window, cx| {
- window.dispatch_action(
- Box::new(ToggleDefaultRule),
- cx,
- );
- }),
- ),
+ .on_click(|_, window, cx| {
+ window.dispatch_action(
+ Box::new(ToggleDefaultRule),
+ cx,
+ );
+ }),
),
),
)
@@ -1228,7 +1206,14 @@ impl RulesLibrary {
.on_action(cx.listener(Self::move_up_from_body))
.flex_grow()
.h_full()
- .child(rule_editor.body_editor.clone()),
+ .child(
+ h_flex()
+ .py_2()
+ .pl_2p5()
+ .h_full()
+ .flex_1()
+ .child(rule_editor.body_editor.clone()),
+ ),
),
)
}))