1use gpui::Hsla;
2
3#[derive(Debug, Clone, Copy)]
4pub struct PlayerColor {
5 pub cursor: Hsla,
6 pub background: Hsla,
7 pub selection: Hsla,
8}
9
10/// A collection of colors that are used to color players in the editor.
11///
12/// The first color is always the local player's color, usually a blue.
13///
14/// The rest of the default colors crisscross back and forth on the
15/// color wheel so that the colors are as distinct as possible.
16#[derive(Clone)]
17pub struct PlayerColors(pub Vec<PlayerColor>);
18
19impl PlayerColors {
20 pub fn local(&self) -> PlayerColor {
21 // todo!("use a valid color");
22 *self.0.first().unwrap()
23 }
24
25 pub fn absent(&self) -> PlayerColor {
26 // todo!("use a valid color");
27 *self.0.last().unwrap()
28 }
29
30 pub fn color_for_participant(&self, participant_index: u32) -> PlayerColor {
31 let len = self.0.len() - 1;
32 self.0[(participant_index as usize % len) + 1]
33 }
34}
35
36#[cfg(feature = "stories")]
37pub use stories::*;
38
39#[cfg(feature = "stories")]
40mod stories {
41 use super::*;
42 use crate::{ActiveTheme, Story};
43 use gpui::{div, img, px, Div, ParentElement, Render, Styled, ViewContext};
44
45 pub struct PlayerStory;
46
47 impl Render for PlayerStory {
48 type Element = Div<Self>;
49
50 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
51 Story::container(cx).child(
52 div()
53 .flex()
54 .flex_col()
55 .gap_4()
56 .child(Story::title_for::<_, PlayerColors>(cx))
57 .child(Story::label(cx, "Player Colors"))
58 .child(
59 div()
60 .flex()
61 .flex_col()
62 .gap_1()
63 .child(
64 div().flex().gap_1().children(
65 cx.theme().players().0.clone().iter_mut().map(|player| {
66 div().w_8().h_8().rounded_md().bg(player.cursor)
67 }),
68 ),
69 )
70 .child(div().flex().gap_1().children(
71 cx.theme().players().0.clone().iter_mut().map(|player| {
72 div().w_8().h_8().rounded_md().bg(player.background)
73 }),
74 ))
75 .child(div().flex().gap_1().children(
76 cx.theme().players().0.clone().iter_mut().map(|player| {
77 div().w_8().h_8().rounded_md().bg(player.selection)
78 }),
79 )),
80 )
81 .child(Story::label(cx, "Avatar Rings"))
82 .child(div().flex().gap_1().children(
83 cx.theme().players().0.clone().iter_mut().map(|player| {
84 div()
85 .my_1()
86 .rounded_full()
87 .border_2()
88 .border_color(player.cursor)
89 .child(
90 img()
91 .rounded_full()
92 .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
93 .size_6()
94 .bg(gpui::red()),
95 )
96 }),
97 ))
98 .child(Story::label(cx, "Player Backgrounds"))
99 .child(div().flex().gap_1().children(
100 cx.theme().players().0.clone().iter_mut().map(|player| {
101 div()
102 .my_1()
103 .rounded_xl()
104 .flex()
105 .items_center()
106 .h_8()
107 .py_0p5()
108 .px_1p5()
109 .bg(player.background)
110 .child(
111 div().relative().neg_mx_1().rounded_full().z_index(3)
112 .border_2()
113 .border_color(player.background)
114 .size(px(28.))
115 .child(
116 img()
117 .rounded_full()
118 .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
119 .size(px(24.))
120 .bg(gpui::red()),
121 ),
122 ).child(
123 div().relative().neg_mx_1().rounded_full().z_index(2)
124 .border_2()
125 .border_color(player.background)
126 .size(px(28.))
127 .child(
128 img()
129 .rounded_full()
130 .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
131 .size(px(24.))
132 .bg(gpui::red()),
133 ),
134 ).child(
135 div().relative().neg_mx_1().rounded_full().z_index(1)
136 .border_2()
137 .border_color(player.background)
138 .size(px(28.))
139 .child(
140 img()
141 .rounded_full()
142 .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
143 .size(px(24.))
144 .bg(gpui::red()),
145 ),
146 )
147 }),
148 ))
149 .child(Story::label(cx, "Player Selections"))
150 .child(div().flex().flex_col().gap_px().children(
151 cx.theme().players().0.clone().iter_mut().map(|player| {
152 div()
153 .flex()
154 .child(
155 div()
156 .flex()
157 .flex_none()
158 .rounded_sm()
159 .px_0p5()
160 .text_color(cx.theme().colors().text)
161 .bg(player.selection)
162 .child("The brown fox jumped over the lazy dog."),
163 )
164 .child(div().flex_1())
165 }),
166 )),
167 )
168 }
169 }
170}