Skip to main content

logicaffeine_web/ui/components/
mode_selector.rs

1use dioxus::prelude::*;
2use crate::ui::components::icon::{Icon, IconVariant, IconSize};
3
4const MODE_SELECTOR_STYLE: &str = r#"
5.mode-overlay {
6    position: fixed;
7    top: 0;
8    left: 0;
9    right: 0;
10    bottom: 0;
11    background: rgba(0, 0, 0, 0.8);
12    display: flex;
13    align-items: center;
14    justify-content: center;
15    z-index: 1000;
16    animation: fade-in 0.2s ease-out;
17}
18
19@keyframes fade-in {
20    from { opacity: 0; }
21    to { opacity: 1; }
22}
23
24.mode-dialog {
25    background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
26    border: 1px solid rgba(255, 255, 255, 0.1);
27    border-radius: 20px;
28    padding: 32px;
29    max-width: 600px;
30    width: 90%;
31    animation: slide-up 0.3s ease-out;
32}
33
34@keyframes slide-up {
35    from { transform: translateY(20px); opacity: 0; }
36    to { transform: translateY(0); opacity: 1; }
37}
38
39.mode-dialog h2 {
40    color: #e8e8e8;
41    font-size: 24px;
42    margin-bottom: 8px;
43    text-align: center;
44}
45
46.mode-dialog p {
47    color: #888;
48    font-size: 14px;
49    text-align: center;
50    margin-bottom: 24px;
51}
52
53.mode-options {
54    display: flex;
55    flex-direction: column;
56    gap: 12px;
57}
58
59.mode-option {
60    display: flex;
61    align-items: center;
62    gap: 16px;
63    padding: 20px;
64    background: rgba(255, 255, 255, 0.03);
65    border: 2px solid rgba(255, 255, 255, 0.08);
66    border-radius: 12px;
67    cursor: pointer;
68    transition: all 0.2s ease;
69}
70
71.mode-option:hover {
72    background: rgba(255, 255, 255, 0.06);
73    border-color: rgba(255, 255, 255, 0.15);
74    transform: translateX(4px);
75}
76
77.mode-option.textbook:hover {
78    border-color: rgba(96, 165, 250, 0.5);
79}
80
81.mode-option.learning:hover {
82    border-color: rgba(74, 222, 128, 0.5);
83}
84
85.mode-option.testing:hover {
86    border-color: rgba(251, 146, 60, 0.5);
87}
88
89.mode-icon {
90    width: 48px;
91    height: 48px;
92    display: flex;
93    align-items: center;
94    justify-content: center;
95    border-radius: 12px;
96    font-size: 24px;
97}
98
99.mode-icon.textbook {
100    background: rgba(96, 165, 250, 0.2);
101}
102
103.mode-icon.learning {
104    background: rgba(74, 222, 128, 0.2);
105}
106
107.mode-icon.testing {
108    background: rgba(251, 146, 60, 0.2);
109}
110
111.mode-info {
112    flex: 1;
113}
114
115.mode-info h3 {
116    color: #e8e8e8;
117    font-size: 18px;
118    margin-bottom: 4px;
119}
120
121.mode-info p {
122    color: #888;
123    font-size: 13px;
124    text-align: left;
125    margin: 0;
126}
127
128.mode-arrow {
129    color: #666;
130    font-size: 20px;
131}
132
133.mode-cancel {
134    display: block;
135    width: 100%;
136    margin-top: 16px;
137    padding: 12px;
138    background: transparent;
139    border: 1px solid rgba(255, 255, 255, 0.1);
140    border-radius: 8px;
141    color: #888;
142    font-size: 14px;
143    cursor: pointer;
144    transition: all 0.2s ease;
145}
146
147.mode-cancel:hover {
148    border-color: rgba(255, 255, 255, 0.2);
149    color: #aaa;
150}
151
152.recommended-badge {
153    background: rgba(74, 222, 128, 0.2);
154    color: #4ade80;
155    padding: 2px 8px;
156    border-radius: 4px;
157    font-size: 10px;
158    font-weight: 600;
159    text-transform: uppercase;
160    margin-left: 8px;
161}
162"#;
163
164#[derive(Clone, PartialEq)]
165pub struct ModeInfo {
166    pub era: String,
167    pub module: String,
168    pub title: String,
169}
170
171#[component]
172pub fn ModeSelector(
173    info: ModeInfo,
174    on_select: EventHandler<String>,
175    on_cancel: EventHandler<()>,
176) -> Element {
177    rsx! {
178        style { "{MODE_SELECTOR_STYLE}" }
179        div {
180            class: "mode-overlay",
181            onclick: move |_| on_cancel.call(()),
182            div {
183                class: "mode-dialog",
184                onclick: move |e| e.stop_propagation(),
185                h2 { "{info.title}" }
186                p { "Choose how you want to approach this module" }
187
188                div { class: "mode-options",
189                    button {
190                        class: "mode-option textbook",
191                        onclick: move |_| on_select.call("textbook".to_string()),
192                        div { class: "mode-icon textbook",
193                            Icon { variant: IconVariant::Book, size: IconSize::Large }
194                        }
195                        div { class: "mode-info",
196                            h3 { "Read" }
197                            p { "Study the concepts and examples before practicing" }
198                        }
199                        span { class: "mode-arrow",
200                            Icon { variant: IconVariant::ChevronRight, size: IconSize::Medium }
201                        }
202                    }
203
204                    button {
205                        class: "mode-option learning",
206                        onclick: move |_| on_select.call("learning".to_string()),
207                        div { class: "mode-icon learning",
208                            Icon { variant: IconVariant::GraduationCap, size: IconSize::Large }
209                        }
210                        div { class: "mode-info",
211                            h3 {
212                                "Practice"
213                                span { class: "recommended-badge", "Recommended" }
214                            }
215                            p { "Learn with hints and immediate feedback on your answers" }
216                        }
217                        span { class: "mode-arrow",
218                            Icon { variant: IconVariant::ChevronRight, size: IconSize::Medium }
219                        }
220                    }
221
222                    button {
223                        class: "mode-option testing",
224                        onclick: move |_| on_select.call("testing".to_string()),
225                        div { class: "mode-icon testing",
226                            Icon { variant: IconVariant::Document, size: IconSize::Large }
227                        }
228                        div { class: "mode-info",
229                            h3 { "Test" }
230                            p { "Prove your knowledge with no hints - see results at the end" }
231                        }
232                        span { class: "mode-arrow",
233                            Icon { variant: IconVariant::ChevronRight, size: IconSize::Medium }
234                        }
235                    }
236                }
237
238                button {
239                    class: "mode-cancel",
240                    onclick: move |_| on_cancel.call(()),
241                    "Cancel"
242                }
243            }
244        }
245    }
246}