perspective_viewer/components/containers/
tab_list.rs1use yew::{Callback, Children, Component, Html, Properties, classes, html};
14
15use crate::components::style::LocalStyle;
16use crate::css;
17
18pub trait Tab: PartialEq + std::fmt::Display + Clone + Default + 'static {}
19
20impl Tab for String {}
21
22impl Tab for &'static str {}
23
24#[derive(Properties, Debug, PartialEq)]
25pub struct TabListProps<T: Tab> {
26 pub tabs: Vec<T>,
28 pub on_tab_change: Callback<(usize, T)>,
29 pub selected_tab: Option<usize>,
30 pub children: Children,
32}
33
34pub enum TabListMsg {
35 SetSelected(usize),
36}
37
38pub struct TabList<T: Tab> {
39 t: std::marker::PhantomData<T>,
40 selected_idx: usize,
41}
42
43impl<T: Tab> Component for TabList<T> {
44 type Message = TabListMsg;
45 type Properties = TabListProps<T>;
46
47 fn create(_ctx: &yew::Context<Self>) -> Self {
48 Self {
49 t: std::marker::PhantomData,
50 selected_idx: 0,
51 }
52 }
53
54 fn update(&mut self, ctx: &yew::Context<Self>, msg: Self::Message) -> bool {
55 match msg {
56 TabListMsg::SetSelected(idx) => {
57 ctx.props()
58 .on_tab_change
59 .emit((idx, ctx.props().tabs[idx].clone()));
60 self.selected_idx = idx;
61 true
62 },
63 }
64 }
65
66 fn changed(&mut self, ctx: &yew::Context<Self>, _old_props: &Self::Properties) -> bool {
67 self.selected_idx = ctx.props().selected_tab.unwrap_or_default();
68 true
69 }
70
71 fn view(&self, ctx: &yew::Context<Self>) -> Html {
72 let p = ctx.props();
73 let gutter_tabs = p.tabs.iter().enumerate().map(|(idx, tab)| {
74 let mut class = classes!("tab");
75 if idx == self.selected_idx {
76 class.push("selected");
77 }
78
79 let onclick = ctx.link().callback(move |_| TabListMsg::SetSelected(idx));
80 html! {
81 <span {class} {onclick}>
82 <div class="tab-title" id={tab.to_string()} />
83 <div class="tab-border" />
84 </span>
85 }
86 });
87
88 html! {
89 <>
90 <LocalStyle href={css!("containers/tabs")} />
91 <div class="tab-gutter">
92 { for gutter_tabs }
93 <span class="tab tab-padding">
94 <div class="tab-title">{ "\u{00a0}" }</div>
95 <div class="tab-border" />
96 </span>
97 </div>
98 <div id="format-tab" class="tab-content">
99 { ctx.props().children.iter().nth(self.selected_idx) }
100 </div>
101 </>
102 }
103 }
104}