1use std::marker::PhantomData;
2
3use crate::prelude::*;
4use crate::{theme, token, SystemColor};
5
6#[derive(Clone, Copy)]
7enum TrafficLightColor {
8 Red,
9 Yellow,
10 Green,
11}
12
13#[derive(Element)]
14struct TrafficLight<S: 'static + Send + Sync> {
15 state_type: PhantomData<S>,
16 color: TrafficLightColor,
17 window_has_focus: bool,
18}
19
20impl<S: 'static + Send + Sync> TrafficLight<S> {
21 fn new(color: TrafficLightColor, window_has_focus: bool) -> Self {
22 Self {
23 state_type: PhantomData,
24 color,
25 window_has_focus,
26 }
27 }
28
29 fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
30 let theme = theme(cx);
31 let system_color = SystemColor::new();
32
33 let fill = match (self.window_has_focus, self.color) {
34 (true, TrafficLightColor::Red) => system_color.mac_os_traffic_light_red,
35 (true, TrafficLightColor::Yellow) => system_color.mac_os_traffic_light_yellow,
36 (true, TrafficLightColor::Green) => system_color.mac_os_traffic_light_green,
37 (false, _) => theme.lowest.base.active.background,
38 };
39
40 div().w_3().h_3().rounded_full().fill(fill)
41 }
42}
43
44#[derive(Element)]
45pub struct TrafficLights<S: 'static + Send + Sync> {
46 state_type: PhantomData<S>,
47 window_has_focus: bool,
48}
49
50impl<S: 'static + Send + Sync> TrafficLights<S> {
51 pub fn new() -> Self {
52 Self {
53 state_type: PhantomData,
54 window_has_focus: true,
55 }
56 }
57
58 pub fn window_has_focus(mut self, window_has_focus: bool) -> Self {
59 self.window_has_focus = window_has_focus;
60 self
61 }
62
63 fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
64 let theme = theme(cx);
65 let token = token();
66
67 div()
68 .flex()
69 .items_center()
70 .gap_2()
71 .child(TrafficLight::new(
72 TrafficLightColor::Red,
73 self.window_has_focus,
74 ))
75 .child(TrafficLight::new(
76 TrafficLightColor::Yellow,
77 self.window_has_focus,
78 ))
79 .child(TrafficLight::new(
80 TrafficLightColor::Green,
81 self.window_has_focus,
82 ))
83 }
84}
85
86#[cfg(feature = "stories")]
87pub use stories::*;
88
89#[cfg(feature = "stories")]
90mod stories {
91 use crate::Story;
92
93 use super::*;
94
95 #[derive(Element)]
96 pub struct TrafficLightsStory<S: 'static + Send + Sync> {
97 state_type: PhantomData<S>,
98 }
99
100 impl<S: 'static + Send + Sync> TrafficLightsStory<S> {
101 pub fn new() -> Self {
102 Self {
103 state_type: PhantomData,
104 }
105 }
106
107 fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
108 Story::container(cx)
109 .child(Story::title_for::<_, TrafficLights<S>>(cx))
110 .child(Story::label(cx, "Default"))
111 .child(TrafficLights::new())
112 .child(Story::label(cx, "Unfocused"))
113 .child(TrafficLights::new().window_has_focus(false))
114 }
115 }
116}