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