ui_storybook/components/recorder/
on_screen_options.rs1use leptos::prelude::*;
6
7use crate::components::menus::{MenuFooter, PopoverPlacement, PopoverSurface};
8use crate::components::primitives::ToggleSwitch;
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub enum OnScreenOptionKind {
15 CleanDesktop,
17 ShowKeys,
19 BlurSensitiveInfo,
21}
22
23impl OnScreenOptionKind {
24 #[must_use]
26 pub fn slug(self) -> &'static str {
27 match self {
28 OnScreenOptionKind::CleanDesktop => "clean-desktop",
29 OnScreenOptionKind::ShowKeys => "show-keys",
30 OnScreenOptionKind::BlurSensitiveInfo => "blur-sensitive-info",
31 }
32 }
33}
34
35#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct OnScreenOptionView {
38 pub id: OnScreenOptionKind,
40 pub title: String,
42 pub description: String,
44 pub enabled: bool,
46 pub disabled: bool,
49}
50
51#[component]
52pub fn OnScreenOptionsPopover(
53 options: Vec<OnScreenOptionView>,
56 #[prop(optional, default = "Applies to this recording")]
59 applies_label: &'static str,
60) -> impl IntoView {
61 let rows: Vec<_> = options.into_iter().map(render_row).collect();
62 view! {
63 <PopoverSurface
64 placement=PopoverPlacement::BottomLeft
65 width_px=380_u16
66 title="On-screen".to_string()
67 description="Choose what shows during recording.".to_string()
68 footer=ToChildren::to_children(move || view! {
69 <MenuFooter>
70 <span style="font-size:11px;color:var(--text-tertiary)">{applies_label}</span>
71 <button class="btn btn-default btn-sm">"Done"</button>
72 </MenuFooter>
73 })
74 >
75 <ul class="on-screen-options" role="group" aria-label="On-screen options">
76 {rows}
77 </ul>
78 </PopoverSurface>
79 }
80}
81
82fn render_row(opt: OnScreenOptionView) -> impl IntoView {
83 let mut class = String::from("on-screen-option-row");
84 if opt.disabled {
85 class.push_str(" on-screen-option-row-disabled");
86 }
87 let toggle_label = format!("Enable {}", opt.title.to_ascii_lowercase());
88 view! {
89 <li class=class data-option=opt.id.slug()>
90 <span class="on-screen-option-toggle">
91 <ToggleSwitch checked=opt.enabled disabled=opt.disabled label=toggle_label />
92 </span>
93 <span class="on-screen-option-text">
94 <span class="on-screen-option-title">{opt.title}</span>
95 <span class="on-screen-option-description">{opt.description}</span>
96 </span>
97 </li>
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn each_kind_has_unique_slug() {
107 let slugs = [
108 OnScreenOptionKind::CleanDesktop.slug(),
109 OnScreenOptionKind::ShowKeys.slug(),
110 OnScreenOptionKind::BlurSensitiveInfo.slug(),
111 ];
112 let mut sorted = slugs.to_vec();
113 sorted.sort_unstable();
114 sorted.dedup();
115 assert_eq!(sorted.len(), slugs.len());
116 }
117
118 #[test]
119 fn slugs_are_kebab_case() {
120 for k in [
121 OnScreenOptionKind::CleanDesktop,
122 OnScreenOptionKind::ShowKeys,
123 OnScreenOptionKind::BlurSensitiveInfo,
124 ] {
125 let s = k.slug();
126 assert!(!s.is_empty());
127 assert!(s.chars().all(|c| c.is_ascii_lowercase() || c == '-'));
128 }
129 }
130}