Skip to main content

ui_storybook/fixtures/
cursor.rs

1//! Cursor Studio fixtures — named cursor styles. Filled in across UI-20.
2
3/// One cursor style the user could select in Cursor Studio.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct CursorStyleFixture {
6    /// Stable id.
7    pub id: &'static str,
8    /// Display label.
9    pub label: &'static str,
10    /// `true` when this is the active style.
11    pub selected: bool,
12}
13
14/// Sample cursor styles.
15#[must_use]
16pub fn sample_cursor_styles() -> Vec<CursorStyleFixture> {
17    vec![
18        CursorStyleFixture {
19            id: "cursor-system",
20            label: "System default",
21            selected: true,
22        },
23        CursorStyleFixture {
24            id: "cursor-soft",
25            label: "Soft ring",
26            selected: false,
27        },
28        CursorStyleFixture {
29            id: "cursor-arrow",
30            label: "Bold arrow",
31            selected: false,
32        },
33        CursorStyleFixture {
34            id: "cursor-spotlight",
35            label: "Spotlight",
36            selected: false,
37        },
38    ]
39}
40
41/// Sample cursor style picker (UI-20).
42#[must_use]
43pub fn sample_cursor_style_picker(
44    selected: crate::components::cursor::CursorStyle,
45) -> crate::components::cursor::CursorStylePickerView {
46    use crate::components::cursor::{CursorStyle, CursorStylePickerView, CursorStyleTileView};
47    let styles = [
48        CursorStyle::System,
49        CursorStyle::Arrow,
50        CursorStyle::Soft,
51        CursorStyle::Dot,
52        CursorStyle::Ring,
53        CursorStyle::Reticle,
54        CursorStyle::Tactile,
55        CursorStyle::Hide,
56    ];
57    let tiles = styles
58        .iter()
59        .map(|s| CursorStyleTileView {
60            style: *s,
61            label: None,
62            selected: *s == selected,
63            disabled: matches!(*s, CursorStyle::Tactile),
64        })
65        .collect();
66    CursorStylePickerView { tiles }
67}
68
69/// Variant where every tile is disabled.
70#[must_use]
71pub fn sample_cursor_style_picker_disabled() -> crate::components::cursor::CursorStylePickerView {
72    use crate::components::cursor::CursorStyle;
73    let mut v = sample_cursor_style_picker(CursorStyle::Arrow);
74    for t in &mut v.tiles {
75        t.disabled = true;
76    }
77    v
78}
79
80/// Sample shell view (UI-20).
81#[must_use]
82pub fn sample_cursor_studio_shell() -> crate::components::cursor::CursorStudioShellView {
83    use crate::components::cursor::{CursorStudioShellView, CursorStyle};
84    CursorStudioShellView {
85        picker: sample_cursor_style_picker(CursorStyle::Arrow),
86    }
87}
88
89/// Sample appearance view (UI-21).
90#[must_use]
91pub fn sample_cursor_appearance() -> crate::components::cursor::CursorAppearanceView {
92    use crate::components::cursor::{
93        ClickEffect, CursorAppearanceView, CursorBehaviorView, CursorColor,
94    };
95    CursorAppearanceView {
96        size_percent: 120,
97        selected_color: CursorColor {
98            label: "Sky",
99            css: "#38bdf8",
100        },
101        halo_enabled: true,
102        halo_strength_percent: 60,
103        click_effect: ClickEffect::Ring,
104        smoothing_percent: 30,
105        trail_enabled: false,
106        behavior: CursorBehaviorView::Natural,
107    }
108}
109
110/// Variant — Pulse click effect.
111#[must_use]
112pub fn sample_cursor_appearance_pulse() -> crate::components::cursor::CursorAppearanceView {
113    use crate::components::cursor::ClickEffect;
114    let mut v = sample_cursor_appearance();
115    v.click_effect = ClickEffect::Pulse;
116    v
117}
118
119/// Variant — Spotlight click effect.
120#[must_use]
121pub fn sample_cursor_appearance_spotlight() -> crate::components::cursor::CursorAppearanceView {
122    use crate::components::cursor::ClickEffect;
123    let mut v = sample_cursor_appearance();
124    v.click_effect = ClickEffect::Spotlight;
125    v
126}
127
128/// Variant — trail on, smoothing high.
129#[must_use]
130pub fn sample_cursor_appearance_trail_on() -> crate::components::cursor::CursorAppearanceView {
131    let mut v = sample_cursor_appearance();
132    v.trail_enabled = true;
133    v.smoothing_percent = 85;
134    v
135}
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140
141    #[test]
142    fn cursor_styles_non_empty_with_one_selected() {
143        let styles = sample_cursor_styles();
144        assert!(!styles.is_empty());
145        assert_eq!(styles.iter().filter(|s| s.selected).count(), 1);
146    }
147}