1// use crate::prelude::*;
2// use crate::{Icon, IconElement, Label, TextColor};
3// use gpui::{prelude::*, red, Div, ElementId, Render, RenderOnce, View};
4
5// #[derive(RenderOnce, Clone)]
6// pub struct Tab {
7// id: ElementId,
8// title: String,
9// icon: Option<Icon>,
10// current: bool,
11// dirty: bool,
12// fs_status: FileSystemStatus,
13// git_status: GitStatus,
14// diagnostic_status: DiagnosticStatus,
15// close_side: IconSide,
16// }
17
18// #[derive(Clone, Debug)]
19// struct TabDragState {
20// title: String,
21// }
22
23// impl Render for TabDragState {
24// type Element = Div;
25
26// fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
27// div().w_8().h_4().bg(red())
28// }
29// }
30
31// impl Component for Tab {
32// type Rendered = gpui::Stateful<Div>;
33
34// fn render(self, cx: &mut WindowContext) -> Self::Rendered {
35// let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict;
36// let is_deleted = self.fs_status == FileSystemStatus::Deleted;
37
38// let label = match (self.git_status, is_deleted) {
39// (_, true) | (GitStatus::Deleted, false) => Label::new(self.title.clone())
40// .color(TextColor::Hidden)
41// .set_strikethrough(true),
42// (GitStatus::None, false) => Label::new(self.title.clone()),
43// (GitStatus::Created, false) => Label::new(self.title.clone()).color(TextColor::Created),
44// (GitStatus::Modified, false) => {
45// Label::new(self.title.clone()).color(TextColor::Modified)
46// }
47// (GitStatus::Renamed, false) => Label::new(self.title.clone()).color(TextColor::Accent),
48// (GitStatus::Conflict, false) => Label::new(self.title.clone()),
49// };
50
51// let close_icon = || IconElement::new(Icon::Close).color(TextColor::Muted);
52
53// let (tab_bg, tab_hover_bg, tab_active_bg) = match self.current {
54// false => (
55// cx.theme().colors().tab_inactive_background,
56// cx.theme().colors().ghost_element_hover,
57// cx.theme().colors().ghost_element_active,
58// ),
59// true => (
60// cx.theme().colors().tab_active_background,
61// cx.theme().colors().element_hover,
62// cx.theme().colors().element_active,
63// ),
64// };
65
66// let drag_state = TabDragState {
67// title: self.title.clone(),
68// };
69
70// div()
71// .id(self.id.clone())
72// .on_drag(move |_view, cx| cx.build_view(|cx| drag_state.clone()))
73// .drag_over::<TabDragState>(|d| d.bg(cx.theme().colors().drop_target_background))
74// .on_drop(|_view, state: View<TabDragState>, cx| {
75// eprintln!("{:?}", state.read(cx));
76// })
77// .px_2()
78// .py_0p5()
79// .flex()
80// .items_center()
81// .justify_center()
82// .bg(tab_bg)
83// .hover(|h| h.bg(tab_hover_bg))
84// .active(|a| a.bg(tab_active_bg))
85// .child(
86// div()
87// .px_1()
88// .flex()
89// .items_center()
90// .gap_1p5()
91// .children(has_fs_conflict.then(|| {
92// IconElement::new(Icon::ExclamationTriangle)
93// .size(crate::IconSize::Small)
94// .color(TextColor::Warning)
95// }))
96// .children(self.icon.map(IconElement::new))
97// .children(if self.close_side == IconSide::Left {
98// Some(close_icon())
99// } else {
100// None
101// })
102// .child(label)
103// .children(if self.close_side == IconSide::Right {
104// Some(close_icon())
105// } else {
106// None
107// }),
108// )
109// }
110// }
111
112// impl Tab {
113// pub fn new(id: impl Into<ElementId>) -> Self {
114// Self {
115// id: id.into(),
116// title: "untitled".to_string(),
117// icon: None,
118// current: false,
119// dirty: false,
120// fs_status: FileSystemStatus::None,
121// git_status: GitStatus::None,
122// diagnostic_status: DiagnosticStatus::None,
123// close_side: IconSide::Right,
124// }
125// }
126
127// pub fn current(mut self, current: bool) -> Self {
128// self.current = current;
129// self
130// }
131
132// pub fn title(mut self, title: String) -> Self {
133// self.title = title;
134// self
135// }
136
137// pub fn icon<I>(mut self, icon: I) -> Self
138// where
139// I: Into<Option<Icon>>,
140// {
141// self.icon = icon.into();
142// self
143// }
144
145// pub fn dirty(mut self, dirty: bool) -> Self {
146// self.dirty = dirty;
147// self
148// }
149
150// pub fn fs_status(mut self, fs_status: FileSystemStatus) -> Self {
151// self.fs_status = fs_status;
152// self
153// }
154
155// pub fn git_status(mut self, git_status: GitStatus) -> Self {
156// self.git_status = git_status;
157// self
158// }
159
160// pub fn diagnostic_status(mut self, diagnostic_status: DiagnosticStatus) -> Self {
161// self.diagnostic_status = diagnostic_status;
162// self
163// }
164
165// pub fn close_side(mut self, close_side: IconSide) -> Self {
166// self.close_side = close_side;
167// self
168// }
169// }
170
171// #[cfg(feature = "stories")]
172// pub use stories::*;
173
174// #[cfg(feature = "stories")]
175// mod stories {
176// use super::*;
177// use crate::{h_stack, v_stack, Icon, Story};
178// use strum::IntoEnumIterator;
179
180// pub struct TabStory;
181
182// impl Render for TabStory {
183// type Element = Div;
184
185// fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
186// let git_statuses = GitStatus::iter();
187// let fs_statuses = FileSystemStatus::iter();
188
189// Story::container(cx)
190// .child(Story::title_for::<_, Tab>(cx))
191// .child(
192// h_stack().child(
193// v_stack()
194// .gap_2()
195// .child(Story::label(cx, "Default"))
196// .child(Tab::new("default")),
197// ),
198// )
199// .child(
200// h_stack().child(
201// v_stack().gap_2().child(Story::label(cx, "Current")).child(
202// h_stack()
203// .gap_4()
204// .child(
205// Tab::new("current")
206// .title("Current".to_string())
207// .current(true),
208// )
209// .child(
210// Tab::new("not_current")
211// .title("Not Current".to_string())
212// .current(false),
213// ),
214// ),
215// ),
216// )
217// .child(
218// h_stack().child(
219// v_stack()
220// .gap_2()
221// .child(Story::label(cx, "Titled"))
222// .child(Tab::new("titled").title("label".to_string())),
223// ),
224// )
225// .child(
226// h_stack().child(
227// v_stack()
228// .gap_2()
229// .child(Story::label(cx, "With Icon"))
230// .child(
231// Tab::new("with_icon")
232// .title("label".to_string())
233// .icon(Some(Icon::Envelope)),
234// ),
235// ),
236// )
237// .child(
238// h_stack().child(
239// v_stack()
240// .gap_2()
241// .child(Story::label(cx, "Close Side"))
242// .child(
243// h_stack()
244// .gap_4()
245// .child(
246// Tab::new("left")
247// .title("Left".to_string())
248// .close_side(IconSide::Left),
249// )
250// .child(Tab::new("right").title("Right".to_string())),
251// ),
252// ),
253// )
254// .child(
255// v_stack()
256// .gap_2()
257// .child(Story::label(cx, "Git Status"))
258// .child(h_stack().gap_4().children(git_statuses.map(|git_status| {
259// Tab::new("git_status")
260// .title(git_status.to_string())
261// .git_status(git_status)
262// }))),
263// )
264// .child(
265// v_stack()
266// .gap_2()
267// .child(Story::label(cx, "File System Status"))
268// .child(h_stack().gap_4().children(fs_statuses.map(|fs_status| {
269// Tab::new("file_system_status")
270// .title(fs_status.to_string())
271// .fs_status(fs_status)
272// }))),
273// )
274// }
275// }
276// }