1use std::marker::PhantomData;
2
3use crate::prelude::*;
4use crate::{theme, 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, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = 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().bg(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, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
64 let theme = theme(cx);
65
66 div()
67 .flex()
68 .items_center()
69 .gap_2()
70 .child(TrafficLight::new(
71 TrafficLightColor::Red,
72 self.window_has_focus,
73 ))
74 .child(TrafficLight::new(
75 TrafficLightColor::Yellow,
76 self.window_has_focus,
77 ))
78 .child(TrafficLight::new(
79 TrafficLightColor::Green,
80 self.window_has_focus,
81 ))
82 }
83}
84
85#[cfg(feature = "stories")]
86pub use stories::*;
87
88#[cfg(feature = "stories")]
89mod stories {
90 use crate::Story;
91
92 use super::*;
93
94 #[derive(Element)]
95 pub struct TrafficLightsStory<S: 'static + Send + Sync> {
96 state_type: PhantomData<S>,
97 }
98
99 impl<S: 'static + Send + Sync> TrafficLightsStory<S> {
100 pub fn new() -> Self {
101 Self {
102 state_type: PhantomData,
103 }
104 }
105
106 fn render(
107 &mut self,
108 _view: &mut S,
109 cx: &mut ViewContext<S>,
110 ) -> impl Element<ViewState = S> {
111 Story::container(cx)
112 .child(Story::title_for::<_, TrafficLights<S>>(cx))
113 .child(Story::label(cx, "Default"))
114 .child(TrafficLights::new())
115 .child(Story::label(cx, "Unfocused"))
116 .child(TrafficLights::new().window_has_focus(false))
117 }
118 }
119}