use crate::core::px;
use crate::view::interactivity::ClickHandler;
use crate::view::prelude::*;
use crate::widgets::separator::horizontal_separator;
use std::rc::Rc;
pub struct Tab {
label: String,
active: bool,
id: Option<String>,
on_click: Option<ClickHandler>,
}
impl Tab {
pub fn new(label: impl Into<String>) -> Self {
Self { label: label.into(), active: false, id: None, on_click: None }
}
pub fn active(mut self, active: bool) -> Self {
self.active = active;
self
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut EventContext) + 'static) -> Self {
self.on_click = Some(Rc::new(handler));
self
}
}
impl IntoElement for Tab {
fn into_element(self) -> AnyElement {
let indicator = if self.active { Token::Accent } else { Token::Surface };
let handler = self.on_click.clone();
div()
.role(Role::Tab)
.label(self.label.clone())
.flex_col()
.h_full()
.bg(if self.active { Token::Canvas } else { Token::Surface })
.hover(|style| style.bg(Token::Hover))
.when_some(self.id, |tab, id| tab.id(id))
.when_some(handler, |tab, handler| tab.cursor_pointer().on_click(move |event, cx| handler(event, cx)))
.child(div().w_full().h(px(2.0)).bg(indicator))
.child(
div()
.flex_1()
.flex_row()
.items_center()
.px_3()
.text_sm()
.text_color(if self.active { Token::Text } else { Token::TextMuted })
.child(self.label),
)
.into_element()
}
}
pub struct TabBar {
tabs: Vec<Tab>,
}
impl TabBar {
pub fn new() -> Self {
Self { tabs: Vec::new() }
}
pub fn tab(mut self, tab: Tab) -> Self {
self.tabs.push(tab);
self
}
}
impl Default for TabBar {
fn default() -> Self {
Self::new()
}
}
impl IntoElement for TabBar {
fn into_element(self) -> AnyElement {
div()
.flex_col()
.w_full()
.h(px(36.0))
.flex_shrink_0()
.bg(Token::Surface)
.child(div().flex_1().flex_row().children(self.tabs))
.child(horizontal_separator())
.into_element()
}
}