Cargo.lock 🔗
@@ -9005,6 +9005,7 @@ dependencies = [
"fs2",
"gpui2",
"indexmap 1.9.3",
+ "itertools 0.11.0",
"parking_lot 0.11.2",
"refineable",
"schemars",
Nate Butler created
[[PR Description]]
- Update the default theme player colors for `Zed Pro Moonlight` and
`Zed Pro Daylight`
- Adds the ability to create stories in the `theme2` crate

You can see them by running:
- `cargo run -p storybook2 -- components/players --theme "Zed Pro
Daylight"`
- `cargo run -p storybook2 -- components/players --theme`
The player colors crisscross back and forth on the color wheel so that
the colors are as distinct as possible.

We do have room to add additional players if needed. Just let me know if
we feel like the default 8 aren't cutting it.
Release Notes:
- N/A
Cargo.lock | 1
crates/storybook2/src/story_selector.rs | 2
crates/theme2/Cargo.toml | 3
crates/theme2/src/colors.rs | 29 ----
crates/theme2/src/default_colors.rs | 159 +++++++++++++++++-------
crates/theme2/src/default_theme.rs | 6
crates/theme2/src/players.rs | 170 ++++++++++++++++++++++++++
crates/theme2/src/story.rs | 38 ++++++
crates/theme2/src/theme2.rs | 7 +
9 files changed, 338 insertions(+), 77 deletions(-)
@@ -9005,6 +9005,7 @@ dependencies = [
"fs2",
"gpui2",
"indexmap 1.9.3",
+ "itertools 0.11.0",
"parking_lot 0.11.2",
"refineable",
"schemars",
@@ -38,6 +38,7 @@ pub enum ComponentStory {
Palette,
Panel,
ProjectPanel,
+ Players,
RecentProjects,
Scroll,
Tab,
@@ -79,6 +80,7 @@ impl ComponentStory {
Self::MultiBuffer => cx.build_view(|_| ui::MultiBufferStory).into(),
Self::NotificationsPanel => cx.build_view(|cx| ui::NotificationsPanelStory).into(),
Self::Palette => cx.build_view(|cx| ui::PaletteStory).into(),
+ Self::Players => cx.build_view(|_| theme2::PlayerStory).into(),
Self::Panel => cx.build_view(|cx| ui::PanelStory).into(),
Self::ProjectPanel => cx.build_view(|_| ui::ProjectPanelStory).into(),
Self::RecentProjects => cx.build_view(|_| ui::RecentProjectsStory).into(),
@@ -5,6 +5,8 @@ edition = "2021"
publish = false
[features]
+default = ["stories"]
+stories = ["dep:itertools"]
test-support = [
"gpui/test-support",
"fs/test-support",
@@ -30,6 +32,7 @@ settings = { package = "settings2", path = "../settings2" }
toml.workspace = true
uuid.workspace = true
util = { path = "../util" }
+itertools = { version = "0.11.0", optional = true }
[dev-dependencies]
gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
@@ -3,7 +3,7 @@ use std::sync::Arc;
use gpui::Hsla;
use refineable::Refineable;
-use crate::SyntaxTheme;
+use crate::{PlayerColors, SyntaxTheme};
#[derive(Clone)]
pub struct SystemColors {
@@ -13,33 +13,6 @@ pub struct SystemColors {
pub mac_os_traffic_light_green: Hsla,
}
-#[derive(Debug, Clone, Copy)]
-pub struct PlayerColor {
- pub cursor: Hsla,
- pub background: Hsla,
- pub selection: Hsla,
-}
-
-#[derive(Clone)]
-pub struct PlayerColors(pub Vec<PlayerColor>);
-
-impl PlayerColors {
- pub fn local(&self) -> PlayerColor {
- // todo!("use a valid color");
- *self.0.first().unwrap()
- }
-
- pub fn absent(&self) -> PlayerColor {
- // todo!("use a valid color");
- *self.0.last().unwrap()
- }
-
- pub fn color_for_participant(&self, participant_index: u32) -> PlayerColor {
- let len = self.0.len() - 1;
- self.0[(participant_index as usize % len) + 1]
- }
-}
-
#[derive(Refineable, Clone, Debug)]
#[refineable(debug)]
pub struct StatusColors {
@@ -3,12 +3,106 @@ use std::num::ParseIntError;
use gpui::{hsla, Hsla, Rgba};
use crate::{
- colors::{GitStatusColors, PlayerColor, PlayerColors, StatusColors, SystemColors, ThemeColors},
+ colors::{GitStatusColors, StatusColors, SystemColors, ThemeColors},
scale::{ColorScaleSet, ColorScales},
syntax::SyntaxTheme,
- ColorScale,
+ ColorScale, PlayerColor, PlayerColors,
};
+impl Default for PlayerColors {
+ fn default() -> Self {
+ Self(vec![
+ PlayerColor {
+ cursor: blue().dark().step_9(),
+ background: blue().dark().step_5(),
+ selection: blue().dark().step_3(),
+ },
+ PlayerColor {
+ cursor: orange().dark().step_9(),
+ background: orange().dark().step_5(),
+ selection: orange().dark().step_3(),
+ },
+ PlayerColor {
+ cursor: pink().dark().step_9(),
+ background: pink().dark().step_5(),
+ selection: pink().dark().step_3(),
+ },
+ PlayerColor {
+ cursor: lime().dark().step_9(),
+ background: lime().dark().step_5(),
+ selection: lime().dark().step_3(),
+ },
+ PlayerColor {
+ cursor: purple().dark().step_9(),
+ background: purple().dark().step_5(),
+ selection: purple().dark().step_3(),
+ },
+ PlayerColor {
+ cursor: amber().dark().step_9(),
+ background: amber().dark().step_5(),
+ selection: amber().dark().step_3(),
+ },
+ PlayerColor {
+ cursor: jade().dark().step_9(),
+ background: jade().dark().step_5(),
+ selection: jade().dark().step_3(),
+ },
+ PlayerColor {
+ cursor: red().dark().step_9(),
+ background: red().dark().step_5(),
+ selection: red().dark().step_3(),
+ },
+ ])
+ }
+}
+
+impl PlayerColors {
+ pub fn default_light() -> Self {
+ Self(vec![
+ PlayerColor {
+ cursor: blue().light().step_9(),
+ background: blue().light().step_4(),
+ selection: blue().light().step_3(),
+ },
+ PlayerColor {
+ cursor: orange().light().step_9(),
+ background: orange().light().step_4(),
+ selection: orange().light().step_3(),
+ },
+ PlayerColor {
+ cursor: pink().light().step_9(),
+ background: pink().light().step_4(),
+ selection: pink().light().step_3(),
+ },
+ PlayerColor {
+ cursor: lime().light().step_9(),
+ background: lime().light().step_4(),
+ selection: lime().light().step_3(),
+ },
+ PlayerColor {
+ cursor: purple().light().step_9(),
+ background: purple().light().step_4(),
+ selection: purple().light().step_3(),
+ },
+ PlayerColor {
+ cursor: amber().light().step_9(),
+ background: amber().light().step_4(),
+ selection: amber().light().step_3(),
+ },
+ PlayerColor {
+ cursor: jade().light().step_9(),
+ background: jade().light().step_4(),
+ selection: jade().light().step_3(),
+ },
+ PlayerColor {
+ cursor: red().light().step_9(),
+ background: red().light().step_4(),
+ selection: red().light().step_3(),
+ },
+ ])
+ }
+}
+
fn neutral() -> ColorScaleSet {
slate()
}
@@ -27,17 +121,17 @@ impl Default for SystemColors {
impl Default for StatusColors {
fn default() -> Self {
Self {
- conflict: red().dark().step_11(),
- 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(),
+ conflict: red().dark().step_9(),
+ created: grass().dark().step_9(),
+ deleted: red().dark().step_9(),
+ error: red().dark().step_9(),
+ hidden: neutral().dark().step_9(),
+ ignored: neutral().dark().step_9(),
+ info: blue().dark().step_9(),
+ modified: yellow().dark().step_9(),
+ renamed: blue().dark().step_9(),
+ success: grass().dark().step_9(),
+ warning: yellow().dark().step_9(),
}
}
}
@@ -45,43 +139,16 @@ impl Default for StatusColors {
impl Default for GitStatusColors {
fn default() -> Self {
Self {
- 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(),
+ conflict: orange().dark().step_9(),
+ created: grass().dark().step_9(),
+ deleted: red().dark().step_9(),
+ ignored: neutral().dark().step_9(),
+ modified: yellow().dark().step_9(),
+ renamed: blue().dark().step_9(),
}
}
}
-impl Default for PlayerColors {
- fn default() -> Self {
- Self(vec![
- PlayerColor {
- cursor: hsla(0.0, 0.0, 0.0, 1.0),
- background: hsla(0.0, 0.0, 0.0, 1.0),
- selection: hsla(0.0, 0.0, 0.0, 1.0),
- },
- PlayerColor {
- cursor: hsla(0.0, 0.0, 0.0, 1.0),
- background: hsla(0.0, 0.0, 0.0, 1.0),
- selection: hsla(0.0, 0.0, 0.0, 1.0),
- },
- PlayerColor {
- cursor: hsla(0.0, 0.0, 0.0, 1.0),
- background: hsla(0.0, 0.0, 0.0, 1.0),
- selection: hsla(0.0, 0.0, 0.0, 1.0),
- },
- PlayerColor {
- cursor: hsla(0.0, 0.0, 0.0, 1.0),
- background: hsla(0.0, 0.0, 0.0, 1.0),
- selection: hsla(0.0, 0.0, 0.0, 1.0),
- },
- ])
- }
-}
-
impl SyntaxTheme {
pub fn default_light() -> Self {
Self {
@@ -1,8 +1,8 @@
use std::sync::Arc;
use crate::{
- colors::{GitStatusColors, PlayerColors, StatusColors, SystemColors, ThemeColors, ThemeStyles},
- default_color_scales, Appearance, SyntaxTheme, Theme, ThemeFamily,
+ colors::{GitStatusColors, StatusColors, SystemColors, ThemeColors, ThemeStyles},
+ default_color_scales, Appearance, PlayerColors, SyntaxTheme, Theme, ThemeFamily,
};
fn zed_pro_daylight() -> Theme {
@@ -15,7 +15,7 @@ fn zed_pro_daylight() -> Theme {
colors: ThemeColors::default_light(),
status: StatusColors::default(),
git: GitStatusColors::default(),
- player: PlayerColors::default(),
+ player: PlayerColors::default_light(),
syntax: Arc::new(SyntaxTheme::default_light()),
},
}
@@ -0,0 +1,170 @@
+use gpui::Hsla;
+
+#[derive(Debug, Clone, Copy)]
+pub struct PlayerColor {
+ pub cursor: Hsla,
+ pub background: Hsla,
+ pub selection: Hsla,
+}
+
+/// A collection of colors that are used to color players in the editor.
+///
+/// The first color is always the local player's color, usually a blue.
+///
+/// The rest of the default colors crisscross back and forth on the
+/// color wheel so that the colors are as distinct as possible.
+#[derive(Clone)]
+pub struct PlayerColors(pub Vec<PlayerColor>);
+
+impl PlayerColors {
+ pub fn local(&self) -> PlayerColor {
+ // todo!("use a valid color");
+ *self.0.first().unwrap()
+ }
+
+ pub fn absent(&self) -> PlayerColor {
+ // todo!("use a valid color");
+ *self.0.last().unwrap()
+ }
+
+ pub fn color_for_participant(&self, participant_index: u32) -> PlayerColor {
+ let len = self.0.len() - 1;
+ self.0[(participant_index as usize % len) + 1]
+ }
+}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use super::*;
+ use crate::{ActiveTheme, Story};
+ use gpui::{div, img, px, Div, ParentElement, Render, Styled, ViewContext};
+
+ pub struct PlayerStory;
+
+ impl Render for PlayerStory {
+ type Element = Div<Self>;
+
+ fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+ Story::container(cx).child(
+ div()
+ .flex()
+ .flex_col()
+ .gap_4()
+ .child(Story::title_for::<_, PlayerColors>(cx))
+ .child(Story::label(cx, "Player Colors"))
+ .child(
+ div()
+ .flex()
+ .flex_col()
+ .gap_1()
+ .child(
+ div().flex().gap_1().children(
+ cx.theme().players().0.clone().iter_mut().map(|player| {
+ div().w_8().h_8().rounded_md().bg(player.cursor)
+ }),
+ ),
+ )
+ .child(div().flex().gap_1().children(
+ cx.theme().players().0.clone().iter_mut().map(|player| {
+ div().w_8().h_8().rounded_md().bg(player.background)
+ }),
+ ))
+ .child(div().flex().gap_1().children(
+ cx.theme().players().0.clone().iter_mut().map(|player| {
+ div().w_8().h_8().rounded_md().bg(player.selection)
+ }),
+ )),
+ )
+ .child(Story::label(cx, "Avatar Rings"))
+ .child(div().flex().gap_1().children(
+ cx.theme().players().0.clone().iter_mut().map(|player| {
+ div()
+ .my_1()
+ .rounded_full()
+ .border_2()
+ .border_color(player.cursor)
+ .child(
+ img()
+ .rounded_full()
+ .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
+ .size_6()
+ .bg(gpui::red()),
+ )
+ }),
+ ))
+ .child(Story::label(cx, "Player Backgrounds"))
+ .child(div().flex().gap_1().children(
+ cx.theme().players().0.clone().iter_mut().map(|player| {
+ div()
+ .my_1()
+ .rounded_xl()
+ .flex()
+ .items_center()
+ .h_8()
+ .py_0p5()
+ .px_1p5()
+ .bg(player.background)
+ .child(
+ div().relative().neg_mx_1().rounded_full().z_index(3)
+ .border_2()
+ .border_color(player.background)
+ .size(px(28.))
+ .child(
+ img()
+ .rounded_full()
+ .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
+ .size(px(24.))
+ .bg(gpui::red()),
+ ),
+ ).child(
+ div().relative().neg_mx_1().rounded_full().z_index(2)
+ .border_2()
+ .border_color(player.background)
+ .size(px(28.))
+ .child(
+ img()
+ .rounded_full()
+ .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
+ .size(px(24.))
+ .bg(gpui::red()),
+ ),
+ ).child(
+ div().relative().neg_mx_1().rounded_full().z_index(1)
+ .border_2()
+ .border_color(player.background)
+ .size(px(28.))
+ .child(
+ img()
+ .rounded_full()
+ .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
+ .size(px(24.))
+ .bg(gpui::red()),
+ ),
+ )
+ }),
+ ))
+ .child(Story::label(cx, "Player Selections"))
+ .child(div().flex().flex_col().gap_px().children(
+ cx.theme().players().0.clone().iter_mut().map(|player| {
+ div()
+ .flex()
+ .child(
+ div()
+ .flex()
+ .flex_none()
+ .rounded_sm()
+ .px_0p5()
+ .text_color(cx.theme().colors().text)
+ .bg(player.selection)
+ .child("The brown fox jumped over the lazy dog."),
+ )
+ .child(div().flex_1())
+ }),
+ )),
+ )
+ }
+ }
+}
@@ -0,0 +1,38 @@
+use gpui::{div, Component, Div, ParentElement, Styled, ViewContext};
+
+use crate::ActiveTheme;
+
+pub struct Story {}
+
+impl Story {
+ pub fn container<V: 'static>(cx: &mut ViewContext<V>) -> Div<V> {
+ div()
+ .size_full()
+ .flex()
+ .flex_col()
+ .pt_2()
+ .px_4()
+ .font("Zed Mono")
+ .bg(cx.theme().colors().background)
+ }
+
+ pub fn title<V: 'static>(cx: &mut ViewContext<V>, title: &str) -> impl Component<V> {
+ div()
+ .text_xl()
+ .text_color(cx.theme().colors().text)
+ .child(title.to_owned())
+ }
+
+ pub fn title_for<V: 'static, T>(cx: &mut ViewContext<V>) -> impl Component<V> {
+ Self::title(cx, std::any::type_name::<T>())
+ }
+
+ pub fn label<V: 'static>(cx: &mut ViewContext<V>, label: &str) -> impl Component<V> {
+ div()
+ .mt_4()
+ .mb_2()
+ .text_xs()
+ .text_color(cx.theme().colors().text)
+ .child(label.to_owned())
+ }
+}
@@ -1,6 +1,7 @@
mod colors;
mod default_colors;
mod default_theme;
+mod players;
mod registry;
mod scale;
mod settings;
@@ -14,6 +15,7 @@ use ::settings::Settings;
pub use colors::*;
pub use default_colors::*;
pub use default_theme::*;
+pub use players::*;
pub use registry::*;
pub use scale::*;
pub use settings::*;
@@ -120,3 +122,8 @@ pub struct DiagnosticStyle {
pub hint: Hsla,
pub ignored: Hsla,
}
+
+#[cfg(feature = "stories")]
+mod story;
+#[cfg(feature = "stories")]
+pub use story::*;