1use std::time::Duration;
7
8use omp_tui::{Component, IntoComponent as _, Key, Prop, Ui, components::Spinner, dom};
9
10pub(crate) const AUTOPLAY_STEP: Duration = Duration::from_millis(1600);
12
13const BARS: &[(&str, &str)] =
14 &[("bar-linear", "linear"), ("bar-in", "in"), ("bar-out", "out"), ("bar-in-out", "in-out")];
15
16const MOODS: &[(&str, &str, &str)] = &[
18 ("ok", "#10231a", "all systems nominal"),
19 ("warn", "#2b2312", "latency rising on shard 7"),
20 ("err", "#2b1414", "shard 7 dropped out"),
21 ("info", "#121f2e", "rebalancing replicas…"),
22];
23
24const PALETTES: &[&str] =
25 &["#0f0c29..#f5af19", "#12c2e9..#f64f59", "#134e5e..#71b280", "#41295a..#f4e2d8"];
26
27pub(crate) fn pane() -> Box<dyn Component> {
29 let (_, mood_bg, mood_text) = MOODS[0];
30 dom! {
31 <col gap=1 pad="1 2">
32 <row gap=2>
33 <text bold fg="#f953c6..#43e97b" spin="4s">{"ANIMATION LAB"}</text>
34 {Spinner::new()}
35 <text dim>{"anim · ease · spin as plain props"}</text>
36 </row>
37 <box title="Easing race" border=round bc=muted pad="0 1">
38 <col>
39 for (id, ease) in BARS {
40 <row gap=1>
41 <text w=7 dim>{*ease}</text>
42 <col id={*id} w=12% h=1 bg=accent anim="900ms" ease={*ease}/>
43 </row>
44 }
45 </col>
46 </box>
47 <row gap=1>
48 <box id=mood grow title="Mood" border=round bleed anim="450ms" bc=ok bg={mood_bg}>
49 <text id="mood-text" fg=ok anim="450ms">{mood_text}</text>
50 </box>
51 <box id=hero grow title="Gradient morph" border=round bleed anim="900ms"
52 ease="in-out" bg={PALETTES[0]} angle=25 spin="6s">
53 <text bold>{"endpoints tween"}</text>
54 <text dim>{"angle spins forever"}</text>
55 </box>
56 </row>
57 <row gap=1>
58 <col id=sidebar w=14 anim="500ms" ease="in-out" bg="#1b2735" pad="0 1">
59 <text bold>{"sidebar"}</text>
60 <text dim>{"w tweens"}</text>
61 </col>
62 <box id=drawer grow h=4 anim="600ms" ease="in-out" border=round bc=muted
63 title="Drawer">
64 <md>{"Height tweens through **layout wakes**: every row below shifts \
65 smoothly.\n\n- retarget mid-flight: it resumes from the screen\n- \
66 first paint never animates\n- settled components request no frames"}</md>
67 </box>
68 </row>
69 <text dim>
70 {"space race · m mood · g gradient · s sidebar · d drawer · a autoplay"}
71 </text>
72 </col>
73 }
74 .into_component()
75}
76
77pub(crate) struct Lab {
79 race_wide: bool,
80 mood: usize,
81 palette: usize,
82 sidebar_wide: bool,
83 drawer_open: bool,
84 pub(crate) autoplay: bool,
85 step: usize,
86}
87
88impl Lab {
89 pub(crate) const fn new() -> Self {
90 Self {
91 race_wide: false,
92 mood: 0,
93 palette: 0,
94 sidebar_wide: false,
95 drawer_open: false,
96 autoplay: true,
97 step: 0,
98 }
99 }
100
101 fn race(&mut self, ui: &mut Ui) {
102 self.race_wide = !self.race_wide;
103 let target = if self.race_wide { "88%" } else { "12%" };
104 for (id, _) in BARS {
105 ui.set_prop(id, Prop::W, target);
106 }
107 }
108
109 fn mood(&mut self, ui: &mut Ui) {
110 self.mood = (self.mood + 1) % MOODS.len();
111 let (token, bg, text) = MOODS[self.mood];
112 ui.set_prop("mood", Prop::Bc, token);
113 ui.set_prop("mood", Prop::Bg, bg);
114 ui.set_prop("mood-text", Prop::Fg, token);
115 ui.set_text("mood-text", text);
116 }
117
118 fn palette(&mut self, ui: &mut Ui) {
119 self.palette = (self.palette + 1) % PALETTES.len();
120 ui.set_prop("hero", Prop::Bg, PALETTES[self.palette]);
121 }
122
123 fn sidebar(&mut self, ui: &mut Ui) {
124 self.sidebar_wide = !self.sidebar_wide;
125 ui.set_prop("sidebar", Prop::W, if self.sidebar_wide { 30_u16 } else { 14 });
126 }
127
128 fn drawer(&mut self, ui: &mut Ui) {
129 self.drawer_open = !self.drawer_open;
130 ui.set_height("drawer", if self.drawer_open { 10 } else { 4 });
131 }
132
133 pub(crate) fn advance(&mut self, ui: &mut Ui) {
135 match self.step % 5 {
136 0 => self.race(ui),
137 1 => self.mood(ui),
138 2 => self.palette(ui),
139 3 => self.sidebar(ui),
140 _ => self.drawer(ui),
141 }
142 self.step += 1;
143 }
144
145 pub(crate) fn handle_key(&mut self, key: Key, ui: &mut Ui) {
147 match key {
148 Key::Space => self.race(ui),
149 Key::Char('m') => self.mood(ui),
150 Key::Char('g') => self.palette(ui),
151 Key::Char('s') => self.sidebar(ui),
152 Key::Char('d') => self.drawer(ui),
153 Key::Char('a') => self.autoplay = !self.autoplay,
154 _ => {},
155 }
156 }
157}