ui_storybook/components/editor/
player_controls.rs1use leptos::prelude::*;
8
9#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
10pub enum PlayState {
11 #[default]
12 Paused,
13 Playing,
14}
15
16#[component]
17pub fn PlayerControls(
18 #[prop(optional)]
20 state: PlayState,
21 #[prop(optional)]
23 position: f32,
24 #[prop(optional)]
26 duration_seconds: f32,
27 #[prop(optional, into)]
32 on_toggle: Option<Callback<()>>,
33) -> impl IntoView {
34 let position = position.clamp(0.0, 1.0);
35 let duration = if duration_seconds <= 0.0 {
36 60.0
37 } else {
38 duration_seconds
39 };
40 let current = position * duration;
41
42 let pct = position * 100.0;
43 let fill_style = format!("width: {pct:.2}%");
44 let handle_style = format!("left: {pct:.2}%");
45
46 let (toggle_glyph, toggle_label, toggle_class) = match state {
47 PlayState::Paused => ("▶", "Play", "player-toggle player-toggle-paused"),
48 PlayState::Playing => ("❚❚", "Pause", "player-toggle player-toggle-playing"),
49 };
50
51 let toggle_click = move |_| {
52 if let Some(cb) = on_toggle {
53 cb.run(());
54 }
55 };
56
57 view! {
58 <div class="player-controls" role="group" aria-label="Player transport">
59 <button class=toggle_class type="button" aria-label=toggle_label on:click=toggle_click>
60 <span class="player-toggle-glyph">{toggle_glyph}</span>
61 </button>
62
63 <div class="player-time" data-role="current">{format_time(current)}</div>
64
65 <div class="player-scrub">
66 <div class="player-scrub-track">
67 <div class="player-scrub-fill" style=fill_style></div>
68 <div class="player-scrub-handle" style=handle_style></div>
69 </div>
70 </div>
71
72 <div class="player-time" data-role="total">{format_time(duration)}</div>
73 </div>
74 }
75}
76
77#[allow(
78 clippy::cast_possible_truncation,
79 clippy::cast_sign_loss,
80 reason = "seconds is positive and bounded by duration_seconds, fits in u32"
81)]
82fn format_time(seconds: f32) -> String {
83 let total = seconds.max(0.0).round() as u32;
84 let m = total / 60;
85 let s = total % 60;
86 format!("{m}:{s:02}")
87}