diff --git a/assets/icons/at-sign.svg b/assets/icons/at-sign.svg
new file mode 100644
index 0000000000..5adac38f62
--- /dev/null
+++ b/assets/icons/at-sign.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/icons/bell-off.svg b/assets/icons/bell-off.svg
new file mode 100644
index 0000000000..db1021f2d3
--- /dev/null
+++ b/assets/icons/bell-off.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/icons/bell-ring.svg b/assets/icons/bell-ring.svg
new file mode 100644
index 0000000000..da51fdc5be
--- /dev/null
+++ b/assets/icons/bell-ring.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/icons/bell.svg b/assets/icons/bell.svg
index ea1c6dd42e..4c7d5472db 100644
--- a/assets/icons/bell.svg
+++ b/assets/icons/bell.svg
@@ -1,8 +1 @@
-
+
\ No newline at end of file
diff --git a/assets/icons/mail-open.svg b/assets/icons/mail-open.svg
new file mode 100644
index 0000000000..b63915bd73
--- /dev/null
+++ b/assets/icons/mail-open.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs
index 3b5722732b..bd97ef1cab 100644
--- a/crates/storybook2/src/storybook2.rs
+++ b/crates/storybook2/src/storybook2.rs
@@ -77,7 +77,7 @@ fn main() {
WindowOptions {
bounds: WindowBounds::Fixed(Bounds {
origin: Default::default(),
- size: size(px(1700.), px(980.)).into(),
+ size: size(px(1500.), px(780.)).into(),
}),
..Default::default()
},
diff --git a/crates/theme2/src/colors.rs b/crates/theme2/src/colors.rs
index 02c93a2e98..ee69eed612 100644
--- a/crates/theme2/src/colors.rs
+++ b/crates/theme2/src/colors.rs
@@ -64,6 +64,7 @@ pub struct ThemeColors {
pub element_selected: Hsla,
pub element_disabled: Hsla,
pub element_placeholder: Hsla,
+ pub element_drop_target: Hsla,
pub ghost_element: Hsla,
pub ghost_element_hover: Hsla,
pub ghost_element_active: Hsla,
@@ -83,6 +84,8 @@ pub struct ThemeColors {
pub title_bar: Hsla,
pub toolbar: Hsla,
pub tab_bar: Hsla,
+ pub tab_inactive: Hsla,
+ pub tab_active: Hsla,
pub editor: Hsla,
pub editor_subheader: Hsla,
pub editor_active_line: Hsla,
diff --git a/crates/theme2/src/default_colors.rs b/crates/theme2/src/default_colors.rs
index 335b6801d5..8b7137683c 100644
--- a/crates/theme2/src/default_colors.rs
+++ b/crates/theme2/src/default_colors.rs
@@ -9,6 +9,10 @@ use crate::{
ColorScale,
};
+fn neutral() -> ColorScaleSet {
+ slate()
+}
+
impl Default for SystemColors {
fn default() -> Self {
Self {
@@ -24,16 +28,16 @@ impl Default for StatusColors {
fn default() -> Self {
Self {
conflict: red().dark().step_11(),
- created: gpui2::black(),
- deleted: gpui2::black(),
- error: gpui2::black(),
- hidden: gpui2::black(),
- ignored: gpui2::black(),
- info: gpui2::black(),
- modified: gpui2::black(),
- renamed: gpui2::black(),
- success: gpui2::black(),
- warning: gpui2::black(),
+ created: grass().dark().step_11(),
+ deleted: red().dark().step_11(),
+ error: red().dark().step_11(),
+ hidden: neutral().dark().step_11(),
+ ignored: neutral().dark().step_11(),
+ info: blue().dark().step_11(),
+ modified: yellow().dark().step_11(),
+ renamed: blue().dark().step_11(),
+ success: grass().dark().step_11(),
+ warning: yellow().dark().step_11(),
}
}
}
@@ -41,12 +45,12 @@ impl Default for StatusColors {
impl Default for GitStatusColors {
fn default() -> Self {
Self {
- conflict: gpui2::rgba(0xdec184ff).into(),
- created: gpui2::rgba(0xa1c181ff).into(),
- deleted: gpui2::rgba(0xd07277ff).into(),
- ignored: gpui2::rgba(0x555a63ff).into(),
- modified: gpui2::rgba(0x74ade8ff).into(),
- renamed: gpui2::rgba(0xdec184ff).into(),
+ conflict: orange().dark().step_11(),
+ created: grass().dark().step_11(),
+ deleted: red().dark().step_11(),
+ ignored: neutral().dark().step_11(),
+ modified: yellow().dark().step_11(),
+ renamed: blue().dark().step_11(),
}
}
}
@@ -82,54 +86,57 @@ impl SyntaxTheme {
pub fn default_light() -> Self {
Self {
highlights: vec![
+ ("attribute".into(), cyan().light().step_11().into()),
+ ("boolean".into(), tomato().light().step_11().into()),
+ ("comment".into(), neutral().light().step_11().into()),
+ ("comment.doc".into(), iris().light().step_12().into()),
+ ("constant".into(), red().light().step_7().into()),
+ ("constructor".into(), red().light().step_7().into()),
+ ("embedded".into(), red().light().step_7().into()),
+ ("emphasis".into(), red().light().step_7().into()),
+ ("emphasis.strong".into(), red().light().step_7().into()),
+ ("enum".into(), red().light().step_7().into()),
+ ("function".into(), red().light().step_7().into()),
+ ("hint".into(), red().light().step_7().into()),
+ ("keyword".into(), orange().light().step_11().into()),
+ ("label".into(), red().light().step_7().into()),
+ ("link_text".into(), red().light().step_7().into()),
+ ("link_uri".into(), red().light().step_7().into()),
+ ("number".into(), red().light().step_7().into()),
+ ("operator".into(), red().light().step_7().into()),
+ ("predictive".into(), red().light().step_7().into()),
+ ("preproc".into(), red().light().step_7().into()),
+ ("primary".into(), red().light().step_7().into()),
+ ("property".into(), red().light().step_7().into()),
+ ("punctuation".into(), neutral().light().step_11().into()),
(
- "string.special.symbol".into(),
- gpui2::rgba(0xad6e26ff).into(),
+ "punctuation.bracket".into(),
+ neutral().light().step_11().into(),
),
- ("hint".into(), gpui2::rgba(0x9294beff).into()),
- ("link_uri".into(), gpui2::rgba(0x3882b7ff).into()),
- ("type".into(), gpui2::rgba(0x3882b7ff).into()),
- ("string.regex".into(), gpui2::rgba(0xad6e26ff).into()),
- ("constant".into(), gpui2::rgba(0x669f59ff).into()),
- ("function".into(), gpui2::rgba(0x5b79e3ff).into()),
- ("string.special".into(), gpui2::rgba(0xad6e26ff).into()),
- ("punctuation.bracket".into(), gpui2::rgba(0x4d4f52ff).into()),
- ("variable".into(), gpui2::rgba(0x383a41ff).into()),
- ("punctuation".into(), gpui2::rgba(0x383a41ff).into()),
- ("property".into(), gpui2::rgba(0xd3604fff).into()),
- ("string".into(), gpui2::rgba(0x649f57ff).into()),
- ("predictive".into(), gpui2::rgba(0x9b9ec6ff).into()),
- ("attribute".into(), gpui2::rgba(0x5c78e2ff).into()),
- ("number".into(), gpui2::rgba(0xad6e25ff).into()),
- ("constructor".into(), gpui2::rgba(0x5c78e2ff).into()),
- ("embedded".into(), gpui2::rgba(0x383a41ff).into()),
- ("title".into(), gpui2::rgba(0xd3604fff).into()),
- ("tag".into(), gpui2::rgba(0x5c78e2ff).into()),
- ("boolean".into(), gpui2::rgba(0xad6e25ff).into()),
- (
- "punctuation.list_marker".into(),
- gpui2::rgba(0xd3604fff).into(),
- ),
- ("variant".into(), gpui2::rgba(0x5b79e3ff).into()),
- ("emphasis".into(), gpui2::rgba(0x5c78e2ff).into()),
- ("link_text".into(), gpui2::rgba(0x5b79e3ff).into()),
- ("comment".into(), gpui2::rgba(0xa2a3a7ff).into()),
- ("punctuation.special".into(), gpui2::rgba(0xb92b46ff).into()),
- ("emphasis.strong".into(), gpui2::rgba(0xad6e25ff).into()),
- ("primary".into(), gpui2::rgba(0x383a41ff).into()),
(
"punctuation.delimiter".into(),
- gpui2::rgba(0x4d4f52ff).into(),
+ neutral().light().step_11().into(),
),
- ("label".into(), gpui2::rgba(0x5c78e2ff).into()),
- ("keyword".into(), gpui2::rgba(0xa449abff).into()),
- ("string.escape".into(), gpui2::rgba(0x7c7e86ff).into()),
- ("text.literal".into(), gpui2::rgba(0x649f57ff).into()),
- ("variable.special".into(), gpui2::rgba(0xad6e25ff).into()),
- ("comment.doc".into(), gpui2::rgba(0x7c7e86ff).into()),
- ("enum".into(), gpui2::rgba(0xd3604fff).into()),
- ("operator".into(), gpui2::rgba(0x3882b7ff).into()),
- ("preproc".into(), gpui2::rgba(0x383a41ff).into()),
+ (
+ "punctuation.list_marker".into(),
+ blue().light().step_11().into(),
+ ),
+ ("punctuation.special".into(), red().light().step_7().into()),
+ ("string".into(), jade().light().step_11().into()),
+ ("string.escape".into(), red().light().step_7().into()),
+ ("string.regex".into(), tomato().light().step_11().into()),
+ ("string.special".into(), red().light().step_7().into()),
+ (
+ "string.special.symbol".into(),
+ red().light().step_7().into(),
+ ),
+ ("tag".into(), red().light().step_7().into()),
+ ("text.literal".into(), red().light().step_7().into()),
+ ("title".into(), red().light().step_7().into()),
+ ("type".into(), red().light().step_7().into()),
+ ("variable".into(), red().light().step_7().into()),
+ ("variable.special".into(), red().light().step_7().into()),
+ ("variant".into(), red().light().step_7().into()),
],
}
}
@@ -137,54 +144,54 @@ impl SyntaxTheme {
pub fn default_dark() -> Self {
Self {
highlights: vec![
- ("keyword".into(), gpui2::rgba(0xb477cfff).into()),
- ("comment.doc".into(), gpui2::rgba(0x878e98ff).into()),
- ("variant".into(), gpui2::rgba(0x73ade9ff).into()),
- ("property".into(), gpui2::rgba(0xd07277ff).into()),
- ("function".into(), gpui2::rgba(0x73ade9ff).into()),
- ("type".into(), gpui2::rgba(0x6eb4bfff).into()),
- ("tag".into(), gpui2::rgba(0x74ade8ff).into()),
- ("string.escape".into(), gpui2::rgba(0x878e98ff).into()),
- ("punctuation.bracket".into(), gpui2::rgba(0xb2b9c6ff).into()),
- ("hint".into(), gpui2::rgba(0x5a6f89ff).into()),
- ("punctuation".into(), gpui2::rgba(0xacb2beff).into()),
- ("comment".into(), gpui2::rgba(0x5d636fff).into()),
- ("emphasis".into(), gpui2::rgba(0x74ade8ff).into()),
- ("punctuation.special".into(), gpui2::rgba(0xb1574bff).into()),
- ("link_uri".into(), gpui2::rgba(0x6eb4bfff).into()),
- ("string.regex".into(), gpui2::rgba(0xbf956aff).into()),
- ("constructor".into(), gpui2::rgba(0x73ade9ff).into()),
- ("operator".into(), gpui2::rgba(0x6eb4bfff).into()),
- ("constant".into(), gpui2::rgba(0xdfc184ff).into()),
- ("string.special".into(), gpui2::rgba(0xbf956aff).into()),
- ("emphasis.strong".into(), gpui2::rgba(0xbf956aff).into()),
+ ("attribute".into(), cyan().dark().step_11().into()),
+ ("boolean".into(), tomato().dark().step_11().into()),
+ ("comment".into(), neutral().dark().step_11().into()),
+ ("comment.doc".into(), iris().dark().step_12().into()),
+ ("constant".into(), red().dark().step_7().into()),
+ ("constructor".into(), red().dark().step_7().into()),
+ ("embedded".into(), red().dark().step_7().into()),
+ ("emphasis".into(), red().dark().step_7().into()),
+ ("emphasis.strong".into(), red().dark().step_7().into()),
+ ("enum".into(), red().dark().step_7().into()),
+ ("function".into(), red().dark().step_7().into()),
+ ("hint".into(), red().dark().step_7().into()),
+ ("keyword".into(), orange().dark().step_11().into()),
+ ("label".into(), red().dark().step_7().into()),
+ ("link_text".into(), red().dark().step_7().into()),
+ ("link_uri".into(), red().dark().step_7().into()),
+ ("number".into(), red().dark().step_7().into()),
+ ("operator".into(), red().dark().step_7().into()),
+ ("predictive".into(), red().dark().step_7().into()),
+ ("preproc".into(), red().dark().step_7().into()),
+ ("primary".into(), red().dark().step_7().into()),
+ ("property".into(), red().dark().step_7().into()),
+ ("punctuation".into(), neutral().dark().step_11().into()),
(
- "string.special.symbol".into(),
- gpui2::rgba(0xbf956aff).into(),
+ "punctuation.bracket".into(),
+ neutral().dark().step_11().into(),
),
- ("primary".into(), gpui2::rgba(0xacb2beff).into()),
- ("preproc".into(), gpui2::rgba(0xc8ccd4ff).into()),
- ("string".into(), gpui2::rgba(0xa1c181ff).into()),
(
"punctuation.delimiter".into(),
- gpui2::rgba(0xb2b9c6ff).into(),
+ neutral().dark().step_11().into(),
),
- ("embedded".into(), gpui2::rgba(0xc8ccd4ff).into()),
- ("enum".into(), gpui2::rgba(0xd07277ff).into()),
- ("variable.special".into(), gpui2::rgba(0xbf956aff).into()),
- ("text.literal".into(), gpui2::rgba(0xa1c181ff).into()),
- ("attribute".into(), gpui2::rgba(0x74ade8ff).into()),
- ("link_text".into(), gpui2::rgba(0x73ade9ff).into()),
- ("title".into(), gpui2::rgba(0xd07277ff).into()),
- ("predictive".into(), gpui2::rgba(0x5a6a87ff).into()),
- ("number".into(), gpui2::rgba(0xbf956aff).into()),
- ("label".into(), gpui2::rgba(0x74ade8ff).into()),
- ("variable".into(), gpui2::rgba(0xc8ccd4ff).into()),
- ("boolean".into(), gpui2::rgba(0xbf956aff).into()),
(
"punctuation.list_marker".into(),
- gpui2::rgba(0xd07277ff).into(),
+ blue().dark().step_11().into(),
),
+ ("punctuation.special".into(), red().dark().step_7().into()),
+ ("string".into(), jade().dark().step_11().into()),
+ ("string.escape".into(), red().dark().step_7().into()),
+ ("string.regex".into(), tomato().dark().step_11().into()),
+ ("string.special".into(), red().dark().step_7().into()),
+ ("string.special.symbol".into(), red().dark().step_7().into()),
+ ("tag".into(), red().dark().step_7().into()),
+ ("text.literal".into(), red().dark().step_7().into()),
+ ("title".into(), red().dark().step_7().into()),
+ ("type".into(), red().dark().step_7().into()),
+ ("variable".into(), red().dark().step_7().into()),
+ ("variable.special".into(), red().dark().step_7().into()),
+ ("variant".into(), red().dark().step_7().into()),
],
}
}
@@ -192,82 +199,92 @@ impl SyntaxTheme {
impl ThemeColors {
pub fn default_light() -> Self {
+ let system = SystemColors::default();
+
Self {
- border: gpui2::white(),
- border_variant: gpui2::white(),
- border_focused: gpui2::white(),
- border_transparent: gpui2::white(),
- elevated_surface: gpui2::white(),
- surface: gpui2::white(),
- background: gpui2::white(),
- element: gpui2::white(),
- element_hover: gpui2::white(),
- element_active: gpui2::white(),
- element_selected: gpui2::white(),
- element_disabled: gpui2::white(),
- element_placeholder: gpui2::white(),
- ghost_element: gpui2::white(),
- ghost_element_hover: gpui2::white(),
- ghost_element_active: gpui2::white(),
- ghost_element_selected: gpui2::white(),
- ghost_element_disabled: gpui2::white(),
- text: gpui2::white(),
- text_muted: gpui2::white(),
- text_placeholder: gpui2::white(),
- text_disabled: gpui2::white(),
- text_accent: gpui2::white(),
- icon: gpui2::white(),
- icon_muted: gpui2::white(),
- icon_disabled: gpui2::white(),
- icon_placeholder: gpui2::white(),
- icon_accent: gpui2::white(),
- status_bar: gpui2::white(),
- title_bar: gpui2::white(),
- toolbar: gpui2::white(),
- tab_bar: gpui2::white(),
- editor: gpui2::white(),
- editor_subheader: gpui2::white(),
- editor_active_line: gpui2::white(),
+ border: neutral().light().step_6(),
+ border_variant: neutral().light().step_5(),
+ border_focused: blue().light().step_5(),
+ border_transparent: system.transparent,
+ elevated_surface: neutral().light().step_2(),
+ surface: neutral().light().step_2(),
+ background: neutral().light().step_1(),
+ element: neutral().light().step_3(),
+ element_hover: neutral().light().step_4(),
+ element_active: neutral().light().step_5(),
+ element_selected: neutral().light().step_5(),
+ element_disabled: neutral().light_alpha().step_3(),
+ element_placeholder: neutral().light().step_11(),
+ element_drop_target: blue().light_alpha().step_2(),
+ ghost_element: system.transparent,
+ ghost_element_hover: neutral().light().step_4(),
+ ghost_element_active: neutral().light().step_5(),
+ ghost_element_selected: neutral().light().step_5(),
+ ghost_element_disabled: neutral().light_alpha().step_3(),
+ text: neutral().light().step_12(),
+ text_muted: neutral().light().step_11(),
+ text_placeholder: neutral().light().step_10(),
+ text_disabled: neutral().light().step_9(),
+ text_accent: blue().light().step_11(),
+ icon: neutral().light().step_11(),
+ icon_muted: neutral().light().step_10(),
+ icon_disabled: neutral().light().step_9(),
+ icon_placeholder: neutral().light().step_10(),
+ icon_accent: blue().light().step_11(),
+ status_bar: neutral().light().step_2(),
+ title_bar: neutral().light().step_2(),
+ toolbar: neutral().light().step_1(),
+ tab_bar: neutral().light().step_2(),
+ tab_active: neutral().light().step_1(),
+ tab_inactive: neutral().light().step_2(),
+ editor: neutral().light().step_1(),
+ editor_subheader: neutral().light().step_2(),
+ editor_active_line: neutral().light_alpha().step_3(),
}
}
pub fn default_dark() -> Self {
+ let system = SystemColors::default();
+
Self {
- border: gpui2::rgba(0x464b57ff).into(),
- border_variant: gpui2::rgba(0x464b57ff).into(),
- border_focused: gpui2::rgba(0x293b5bff).into(),
- border_transparent: gpui2::rgba(0x00000000).into(),
- elevated_surface: gpui2::rgba(0x3b414dff).into(),
- surface: gpui2::rgba(0x2f343eff).into(),
- background: gpui2::rgba(0x3b414dff).into(),
- element: gpui2::rgba(0x3b414dff).into(),
- element_hover: gpui2::rgba(0xffffff1e).into(),
- element_active: gpui2::rgba(0xffffff28).into(),
- element_selected: gpui2::rgba(0x18243dff).into(),
- element_disabled: gpui2::rgba(0x00000000).into(),
- element_placeholder: gpui2::black(),
- ghost_element: gpui2::rgba(0x00000000).into(),
- ghost_element_hover: gpui2::rgba(0xffffff14).into(),
- ghost_element_active: gpui2::rgba(0xffffff1e).into(),
- ghost_element_selected: gpui2::rgba(0x18243dff).into(),
- ghost_element_disabled: gpui2::rgba(0x00000000).into(),
- text: gpui2::rgba(0xc8ccd4ff).into(),
- text_muted: gpui2::rgba(0x838994ff).into(),
- text_placeholder: gpui2::rgba(0xd07277ff).into(),
- text_disabled: gpui2::rgba(0x555a63ff).into(),
- text_accent: gpui2::rgba(0x74ade8ff).into(),
- icon: gpui2::black(),
- icon_muted: gpui2::rgba(0x838994ff).into(),
- icon_disabled: gpui2::black(),
- icon_placeholder: gpui2::black(),
- icon_accent: gpui2::black(),
- status_bar: gpui2::rgba(0x3b414dff).into(),
- title_bar: gpui2::rgba(0x3b414dff).into(),
- toolbar: gpui2::rgba(0x282c33ff).into(),
- tab_bar: gpui2::rgba(0x2f343eff).into(),
- editor: gpui2::rgba(0x282c33ff).into(),
- editor_subheader: gpui2::rgba(0x2f343eff).into(),
- editor_active_line: gpui2::rgba(0x2f343eff).into(),
+ border: neutral().dark().step_6(),
+ border_variant: neutral().dark().step_5(),
+ border_focused: blue().dark().step_5(),
+ border_transparent: system.transparent,
+ elevated_surface: neutral().dark().step_2(),
+ surface: neutral().dark().step_2(),
+ background: neutral().dark().step_1(),
+ element: neutral().dark().step_3(),
+ element_hover: neutral().dark().step_4(),
+ element_active: neutral().dark().step_5(),
+ element_selected: neutral().dark().step_5(),
+ element_disabled: neutral().dark_alpha().step_3(),
+ element_placeholder: neutral().dark().step_11(),
+ element_drop_target: blue().dark_alpha().step_2(),
+ ghost_element: system.transparent,
+ ghost_element_hover: neutral().dark().step_4(),
+ ghost_element_active: neutral().dark().step_5(),
+ ghost_element_selected: neutral().dark().step_5(),
+ ghost_element_disabled: neutral().dark_alpha().step_3(),
+ text: neutral().dark().step_12(),
+ text_muted: neutral().dark().step_11(),
+ text_placeholder: neutral().dark().step_10(),
+ text_disabled: neutral().dark().step_9(),
+ text_accent: blue().dark().step_11(),
+ icon: neutral().dark().step_11(),
+ icon_muted: neutral().dark().step_10(),
+ icon_disabled: neutral().dark().step_9(),
+ icon_placeholder: neutral().dark().step_10(),
+ icon_accent: blue().dark().step_11(),
+ status_bar: neutral().dark().step_2(),
+ title_bar: neutral().dark().step_2(),
+ toolbar: neutral().dark().step_1(),
+ tab_bar: neutral().dark().step_2(),
+ tab_active: neutral().dark().step_1(),
+ tab_inactive: neutral().dark().step_2(),
+ editor: neutral().dark().step_1(),
+ editor_subheader: neutral().dark().step_2(),
+ editor_active_line: neutral().dark_alpha().step_3(),
}
}
}
diff --git a/crates/theme2/src/theme2.rs b/crates/theme2/src/theme2.rs
index 34727eaf89..88dcbd1286 100644
--- a/crates/theme2/src/theme2.rs
+++ b/crates/theme2/src/theme2.rs
@@ -70,6 +70,18 @@ impl ThemeVariant {
&self.styles.syntax
}
+ /// Returns the [`StatusColors`] for the theme.
+ #[inline(always)]
+ pub fn status(&self) -> &StatusColors {
+ &self.styles.status
+ }
+
+ /// Returns the [`GitStatusColors`] for the theme.
+ #[inline(always)]
+ pub fn git(&self) -> &GitStatusColors {
+ &self.styles.git
+ }
+
/// Returns the color for the syntax node with the given name.
#[inline(always)]
pub fn syntax_color(&self, name: &str) -> Hsla {
diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs
index 1668592a38..50a86ff256 100644
--- a/crates/ui2/src/components/list.rs
+++ b/crates/ui2/src/components/list.rs
@@ -1,4 +1,4 @@
-use gpui2::{div, relative, Div};
+use gpui2::{div, px, relative, Div};
use crate::settings::user_settings;
use crate::{
@@ -15,12 +15,20 @@ pub enum ListItemVariant {
Inset,
}
+pub enum ListHeaderMeta {
+ // TODO: These should be IconButtons
+ Tools(Vec),
+ // TODO: This should be a button
+ Button(Label),
+ Text(Label),
+}
+
#[derive(Component)]
pub struct ListHeader {
label: SharedString,
left_icon: Option,
+ meta: Option,
variant: ListItemVariant,
- state: InteractionState,
toggleable: Toggleable,
}
@@ -29,9 +37,9 @@ impl ListHeader {
Self {
label: label.into(),
left_icon: None,
+ meta: None,
variant: ListItemVariant::default(),
- state: InteractionState::default(),
- toggleable: Toggleable::Toggleable(ToggleState::Toggled),
+ toggleable: Toggleable::NotToggleable,
}
}
@@ -50,8 +58,8 @@ impl ListHeader {
self
}
- pub fn state(mut self, state: InteractionState) -> Self {
- self.state = state;
+ pub fn meta(mut self, meta: Option) -> Self {
+ self.meta = meta;
self
}
@@ -74,34 +82,36 @@ impl ListHeader {
}
}
- fn label_color(&self) -> LabelColor {
- match self.state {
- InteractionState::Disabled => LabelColor::Disabled,
- _ => Default::default(),
- }
- }
-
- fn icon_color(&self) -> IconColor {
- match self.state {
- InteractionState::Disabled => IconColor::Disabled,
- _ => Default::default(),
- }
- }
-
fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component {
let is_toggleable = self.toggleable != Toggleable::NotToggleable;
let is_toggled = self.toggleable.is_toggled();
let disclosure_control = self.disclosure_control();
+ let meta = match self.meta {
+ Some(ListHeaderMeta::Tools(icons)) => div().child(
+ h_stack()
+ .gap_2()
+ .items_center()
+ .children(icons.into_iter().map(|i| {
+ IconElement::new(i)
+ .color(IconColor::Muted)
+ .size(IconSize::Small)
+ })),
+ ),
+ Some(ListHeaderMeta::Button(label)) => div().child(label),
+ Some(ListHeaderMeta::Text(label)) => div().child(label),
+ None => div(),
+ };
+
h_stack()
- .flex_1()
.w_full()
.bg(cx.theme().colors().surface)
- .when(self.state == InteractionState::Focused, |this| {
- this.border()
- .border_color(cx.theme().colors().border_focused)
- })
+ // TODO: Add focus state
+ // .when(self.state == InteractionState::Focused, |this| {
+ // this.border()
+ // .border_color(cx.theme().colors().border_focused)
+ // })
.relative()
.child(
div()
@@ -109,22 +119,28 @@ impl ListHeader {
.when(self.variant == ListItemVariant::Inset, |this| this.px_2())
.flex()
.flex_1()
+ .items_center()
+ .justify_between()
.w_full()
.gap_1()
- .items_center()
.child(
- div()
- .flex()
+ h_stack()
.gap_1()
- .items_center()
- .children(self.left_icon.map(|i| {
- IconElement::new(i)
- .color(IconColor::Muted)
- .size(IconSize::Small)
- }))
- .child(Label::new(self.label.clone()).color(LabelColor::Muted)),
+ .child(
+ div()
+ .flex()
+ .gap_1()
+ .items_center()
+ .children(self.left_icon.map(|i| {
+ IconElement::new(i)
+ .color(IconColor::Muted)
+ .size(IconSize::Small)
+ }))
+ .child(Label::new(self.label.clone()).color(LabelColor::Muted)),
+ )
+ .child(disclosure_control),
)
- .child(disclosure_control),
+ .child(meta),
)
}
}
@@ -473,42 +489,63 @@ impl ListDetailsEntry {
fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component {
let settings = user_settings(cx);
- let (item_bg, item_bg_hover, item_bg_active) = match self.seen {
- true => (
- cx.theme().colors().ghost_element,
- cx.theme().colors().ghost_element_hover,
- cx.theme().colors().ghost_element_active,
- ),
- false => (
- cx.theme().colors().element,
- cx.theme().colors().element_hover,
- cx.theme().colors().element_active,
- ),
- };
+ let (item_bg, item_bg_hover, item_bg_active) = (
+ cx.theme().colors().ghost_element,
+ cx.theme().colors().ghost_element_hover,
+ cx.theme().colors().ghost_element_active,
+ );
let label_color = match self.seen {
true => LabelColor::Muted,
false => LabelColor::Default,
};
- v_stack()
+ div()
.relative()
.group("")
.bg(item_bg)
- .px_1()
- .py_1_5()
+ .px_2()
+ .py_1p5()
.w_full()
- .line_height(relative(1.2))
- .child(Label::new(self.label.clone()).color(label_color))
- .children(
- self.meta
- .map(|meta| Label::new(meta).color(LabelColor::Muted)),
- )
+ .z_index(1)
+ .when(!self.seen, |this| {
+ this.child(
+ div()
+ .absolute()
+ .left(px(3.0))
+ .top_3()
+ .rounded_full()
+ .border_2()
+ .border_color(cx.theme().colors().surface)
+ .w(px(9.0))
+ .h(px(9.0))
+ .z_index(2)
+ .bg(cx.theme().status().info),
+ )
+ })
.child(
- h_stack()
+ v_stack()
+ .w_full()
+ .line_height(relative(1.2))
.gap_1()
- .justify_end()
- .children(self.actions.unwrap_or_default()),
+ .child(
+ div()
+ .w_5()
+ .h_5()
+ .rounded_full()
+ .bg(cx.theme().colors().icon_accent),
+ )
+ .child(Label::new(self.label.clone()).color(label_color))
+ .children(
+ self.meta
+ .map(|meta| Label::new(meta).color(LabelColor::Muted)),
+ )
+ .child(
+ h_stack()
+ .gap_1()
+ .justify_end()
+ .children(self.actions.unwrap_or_default()),
+ ),
)
}
}
@@ -522,7 +559,7 @@ impl ListSeparator {
}
fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component {
- div().h_px().w_full().bg(cx.theme().colors().border)
+ div().h_px().w_full().bg(cx.theme().colors().border_variant)
}
}
@@ -564,14 +601,15 @@ impl List {
let is_toggled = Toggleable::is_toggled(&self.toggleable);
let list_content = match (self.items.is_empty(), is_toggled) {
- (_, false) => div(),
(false, _) => div().children(self.items),
- (true, _) => {
+ (true, false) => div(),
+ (true, true) => {
div().child(Label::new(self.empty_message.clone()).color(LabelColor::Muted))
}
};
v_stack()
+ .w_full()
.py_1()
.children(self.header.map(|header| header.toggleable(self.toggleable)))
.child(list_content)
diff --git a/crates/ui2/src/components/notifications_panel.rs b/crates/ui2/src/components/notifications_panel.rs
index 10b0e07af6..74f015ac06 100644
--- a/crates/ui2/src/components/notifications_panel.rs
+++ b/crates/ui2/src/components/notifications_panel.rs
@@ -1,5 +1,10 @@
-use crate::{prelude::*, static_new_notification_items, static_read_notification_items};
-use crate::{List, ListHeader};
+use crate::utils::naive_format_distance_from_now;
+use crate::{
+ h_stack, prelude::*, static_new_notification_items_2, v_stack, Avatar, Button, Icon,
+ IconButton, IconElement, Label, LabelColor, LineHeightStyle, ListHeaderMeta, ListSeparator,
+ UnreadIndicator,
+};
+use crate::{ClickHandler, ListHeader};
#[derive(Component)]
pub struct NotificationsPanel {
@@ -16,31 +21,348 @@ impl NotificationsPanel {
.id(self.id.clone())
.flex()
.flex_col()
- .w_full()
- .h_full()
+ .size_full()
.bg(cx.theme().colors().surface)
.child(
- div()
- .id("header")
- .w_full()
- .flex()
- .flex_col()
+ ListHeader::new("Notifications").meta(Some(ListHeaderMeta::Tools(vec![
+ Icon::AtSign,
+ Icon::BellOff,
+ Icon::MailOpen,
+ ]))),
+ )
+ .child(ListSeparator::new())
+ .child(
+ v_stack()
+ .id("notifications-panel-scroll-view")
+ .py_1()
.overflow_y_scroll()
+ .flex_1()
.child(
- List::new(static_new_notification_items())
- .header(ListHeader::new("NEW").toggle(ToggleState::Toggled))
- .toggle(ToggleState::Toggled),
+ div()
+ .mx_2()
+ .p_1()
+ // TODO: Add cursor style
+ // .cursor(Cursor::IBeam)
+ .bg(cx.theme().colors().element)
+ .border()
+ .border_color(cx.theme().colors().border_variant)
+ .child(
+ Label::new("Search...")
+ .color(LabelColor::Placeholder)
+ .line_height_style(LineHeightStyle::UILabel),
+ ),
+ )
+ .child(v_stack().px_1().children(static_new_notification_items_2())),
+ )
+ }
+}
+
+pub enum ButtonOrIconButton {
+ Button(Button),
+ IconButton(IconButton),
+}
+
+impl From