qorzen_oxide/ui/pages/settings.rs
1// src/ui/pages/settings.rs - Application settings and configuration
2
3use dioxus::prelude::*;
4
5use crate::ui::pages::PageWrapper;
6
7/// Main settings page component
8#[component]
9pub fn Settings() -> Element {
10 let mut active_section = use_signal(|| "general".to_string());
11
12 rsx! {
13 PageWrapper {
14 title: "Settings".to_string(),
15 subtitle: Some("Configure your application preferences".to_string()),
16
17 div {
18 class: "lg:grid lg:grid-cols-12 lg:gap-x-8",
19
20 // Settings navigation
21 aside {
22 class: "py-6 px-2 sm:px-6 lg:py-0 lg:px-0 lg:col-span-3",
23 nav {
24 class: "space-y-1",
25
26 // General
27 button {
28 r#type: "button",
29 class: format!(
30 "group rounded-md px-3 py-2 flex items-center text-sm font-medium w-full text-left {}",
31 if active_section() == "general" {
32 "bg-blue-50 text-blue-700 hover:text-blue-700 hover:bg-blue-50"
33 } else {
34 "text-gray-900 hover:text-gray-900 hover:bg-gray-50"
35 }
36 ),
37 onclick: move |_| active_section.set("general".to_string()),
38 span {
39 class: "text-lg mr-3",
40 "⚙️"
41 }
42 "General"
43 }
44
45 // Appearance
46 button {
47 r#type: "button",
48 class: format!(
49 "group rounded-md px-3 py-2 flex items-center text-sm font-medium w-full text-left {}",
50 if active_section() == "appearance" {
51 "bg-blue-50 text-blue-700 hover:text-blue-700 hover:bg-blue-50"
52 } else {
53 "text-gray-900 hover:text-gray-900 hover:bg-gray-50"
54 }
55 ),
56 onclick: move |_| active_section.set("appearance".to_string()),
57 span {
58 class: "text-lg mr-3",
59 "🎨"
60 }
61 "Appearance"
62 }
63
64 // Notifications
65 button {
66 r#type: "button",
67 class: format!(
68 "group rounded-md px-3 py-2 flex items-center text-sm font-medium w-full text-left {}",
69 if active_section() == "notifications" {
70 "bg-blue-50 text-blue-700 hover:text-blue-700 hover:bg-blue-50"
71 } else {
72 "text-gray-900 hover:text-gray-900 hover:bg-gray-50"
73 }
74 ),
75 onclick: move |_| active_section.set("notifications".to_string()),
76 span {
77 class: "text-lg mr-3",
78 "🔔"
79 }
80 "Notifications"
81 }
82
83 // Security
84 button {
85 r#type: "button",
86 class: format!(
87 "group rounded-md px-3 py-2 flex items-center text-sm font-medium w-full text-left {}",
88 if active_section() == "security" {
89 "bg-blue-50 text-blue-700 hover:text-blue-700 hover:bg-blue-50"
90 } else {
91 "text-gray-900 hover:text-gray-900 hover:bg-gray-50"
92 }
93 ),
94 onclick: move |_| active_section.set("security".to_string()),
95 span {
96 class: "text-lg mr-3",
97 "🔒"
98 }
99 "Security"
100 }
101
102 // System
103 button {
104 r#type: "button",
105 class: format!(
106 "group rounded-md px-3 py-2 flex items-center text-sm font-medium w-full text-left {}",
107 if active_section() == "system" {
108 "bg-blue-50 text-blue-700 hover:text-blue-700 hover:bg-blue-50"
109 } else {
110 "text-gray-900 hover:text-gray-900 hover:bg-gray-50"
111 }
112 ),
113 onclick: move |_| active_section.set("system".to_string()),
114 span {
115 class: "text-lg mr-3",
116 "🖥️"
117 }
118 "System"
119 }
120
121 // About
122 button {
123 r#type: "button",
124 class: format!(
125 "group rounded-md px-3 py-2 flex items-center text-sm font-medium w-full text-left {}",
126 if active_section() == "about" {
127 "bg-blue-50 text-blue-700 hover:text-blue-700 hover:bg-blue-50"
128 } else {
129 "text-gray-900 hover:text-gray-900 hover:bg-gray-50"
130 }
131 ),
132 onclick: move |_| active_section.set("about".to_string()),
133 span {
134 class: "text-lg mr-3",
135 "ℹ️"
136 }
137 "About"
138 }
139 }
140 }
141
142 // Settings content
143 main {
144 class: "lg:col-span-9",
145 match active_section().as_str() {
146 "general" => rsx! { GeneralSettings {} },
147 "appearance" => rsx! { AppearanceSettings {} },
148 "notifications" => rsx! { NotificationSettings {} },
149 "security" => rsx! { SecuritySettings {} },
150 "system" => rsx! { SystemSettings {} },
151 "about" => rsx! { AboutSettings {} },
152 _ => rsx! { div { "Unknown section" } }
153 }
154 }
155 }
156 }
157 }
158}
159
160/// General settings section
161#[component]
162fn GeneralSettings() -> Element {
163 let mut language = use_signal(|| "en".to_string());
164 let mut timezone = use_signal(|| "UTC".to_string());
165 let mut date_format = use_signal(|| "MM/DD/YYYY".to_string());
166 let mut time_format = use_signal(|| "12h".to_string());
167 let mut auto_save = use_signal(|| true);
168 let mut saving = use_signal(|| false);
169
170 let handle_save = {
171 move |_| {
172 saving.set(true);
173 spawn(async move {
174 #[cfg(not(target_arch = "wasm32"))]
175 tokio::time::sleep(std::time::Duration::from_millis(1000)).await;
176 #[cfg(target_arch = "wasm32")]
177 gloo_timers::future::TimeoutFuture::new(1000).await;
178 saving.set(false);
179 });
180 }
181 };
182
183 rsx! {
184 div {
185 class: "space-y-6",
186
187 // Section header
188 div {
189 class: "bg-white shadow px-4 py-5 sm:rounded-lg sm:p-6",
190 div {
191 class: "md:grid md:grid-cols-3 md:gap-6",
192 div {
193 class: "md:col-span-1",
194 h3 {
195 class: "text-lg font-medium leading-6 text-gray-900",
196 "General Settings"
197 }
198 p {
199 class: "mt-1 text-sm text-gray-500",
200 "Configure basic application preferences and regional settings."
201 }
202 }
203 div {
204 class: "mt-5 md:mt-0 md:col-span-2",
205 form {
206 class: "space-y-6",
207 onsubmit: handle_save,
208
209 // Language selection
210 div {
211 label {
212 r#for: "language",
213 class: "block text-sm font-medium text-gray-700",
214 "Language"
215 }
216 select {
217 id: "language",
218 name: "language",
219 class: "mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md",
220 value: "{language}",
221 onchange: move |e| language.set(e.value()),
222 option { value: "en", "English" }
223 option { value: "es", "Español" }
224 option { value: "fr", "Français" }
225 option { value: "de", "Deutsch" }
226 option { value: "ja", "日本語" }
227 option { value: "zh", "中文" }
228 }
229 }
230
231 // Timezone selection
232 div {
233 label {
234 r#for: "timezone",
235 class: "block text-sm font-medium text-gray-700",
236 "Timezone"
237 }
238 select {
239 id: "timezone",
240 name: "timezone",
241 class: "mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md",
242 value: "{timezone}",
243 onchange: move |e| timezone.set(e.value()),
244 option { value: "UTC", "UTC (Coordinated Universal Time)" }
245 option { value: "America/New_York", "Eastern Time (ET)" }
246 option { value: "America/Chicago", "Central Time (CT)" }
247 option { value: "America/Denver", "Mountain Time (MT)" }
248 option { value: "America/Los_Angeles", "Pacific Time (PT)" }
249 option { value: "Europe/London", "London (GMT)" }
250 option { value: "Europe/Paris", "Paris (CET)" }
251 option { value: "Asia/Tokyo", "Tokyo (JST)" }
252 }
253 }
254
255 // Date format
256 div {
257 label {
258 r#for: "date_format",
259 class: "block text-sm font-medium text-gray-700",
260 "Date Format"
261 }
262 select {
263 id: "date_format",
264 name: "date_format",
265 class: "mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md",
266 value: "{date_format}",
267 onchange: move |e| date_format.set(e.value()),
268 option { value: "MM/DD/YYYY", "MM/DD/YYYY (12/31/2024)" }
269 option { value: "DD/MM/YYYY", "DD/MM/YYYY (31/12/2024)" }
270 option { value: "YYYY-MM-DD", "YYYY-MM-DD (2024-12-31)" }
271 option { value: "DD.MM.YYYY", "DD.MM.YYYY (31.12.2024)" }
272 }
273 }
274
275 // Time format
276 div {
277 label {
278 r#for: "time_format",
279 class: "block text-sm font-medium text-gray-700",
280 "Time Format"
281 }
282 select {
283 id: "time_format",
284 name: "time_format",
285 class: "mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md",
286 value: "{time_format}",
287 onchange: move |e| time_format.set(e.value()),
288 option { value: "12h", "12-hour (2:30 PM)" }
289 option { value: "24h", "24-hour (14:30)" }
290 }
291 }
292
293 // Auto-save toggle
294 div {
295 class: "flex items-center justify-between",
296 div {
297 class: "flex flex-col",
298 label {
299 r#for: "auto_save",
300 class: "text-sm font-medium text-gray-700",
301 "Auto-save"
302 }
303 p {
304 class: "text-sm text-gray-500",
305 "Automatically save changes as you work"
306 }
307 }
308 button {
309 r#type: "button",
310 class: format!(
311 "relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 {}",
312 if auto_save() { "bg-blue-600" } else { "bg-gray-200" }
313 ),
314 onclick: move |_| auto_save.set(!auto_save()),
315 span {
316 class: format!(
317 "pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200 {}",
318 if auto_save() { "translate-x-5" } else { "translate-x-0" }
319 )
320 }
321 }
322 }
323
324 // Save button
325 div {
326 class: "flex justify-end",
327 button {
328 r#type: "submit",
329 class: "bg-blue-600 border border-transparent rounded-md shadow-sm py-2 px-4 inline-flex justify-center text-sm font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50",
330 disabled: saving(),
331 if saving() { "Saving..." } else { "Save Changes" }
332 }
333 }
334 }
335 }
336 }
337 }
338 }
339 }
340}
341
342/// Appearance settings section
343#[component]
344fn AppearanceSettings() -> Element {
345 let mut theme = use_signal(|| "light".to_string());
346 let mut sidebar_collapsed = use_signal(|| false);
347 let mut compact_mode = use_signal(|| false);
348 let mut animations = use_signal(|| true);
349
350 rsx! {
351 div {
352 class: "space-y-6",
353
354 div {
355 class: "bg-white shadow px-4 py-5 sm:rounded-lg sm:p-6",
356 div {
357 class: "md:grid md:grid-cols-3 md:gap-6",
358 div {
359 class: "md:col-span-1",
360 h3 {
361 class: "text-lg font-medium leading-6 text-gray-900",
362 "Appearance"
363 }
364 p {
365 class: "mt-1 text-sm text-gray-500",
366 "Customize the look and feel of your application."
367 }
368 }
369 div {
370 class: "mt-5 md:mt-0 md:col-span-2",
371 div {
372 class: "space-y-6",
373
374 // Theme selection
375 div {
376 label {
377 class: "block text-sm font-medium text-gray-700",
378 "Theme"
379 }
380 div {
381 class: "mt-2 grid grid-cols-3 gap-3 sm:grid-cols-3",
382
383 // Light theme
384 label {
385 class: format!(
386 "cursor-pointer relative flex items-center justify-center rounded-md border py-3 px-3 text-sm font-medium uppercase hover:bg-gray-50 focus:outline-none {}",
387 if theme() == "light" {
388 "bg-blue-50 border-blue-200 text-blue-900"
389 } else {
390 "bg-white border-gray-200 text-gray-900"
391 }
392 ),
393 input {
394 r#type: "radio",
395 name: "theme",
396 value: "light",
397 class: "sr-only",
398 checked: theme() == "light",
399 onchange: move |_| theme.set("light".to_string())
400 }
401 span { "☀️ Light" }
402 }
403
404 // Dark theme
405 label {
406 class: format!(
407 "cursor-pointer relative flex items-center justify-center rounded-md border py-3 px-3 text-sm font-medium uppercase hover:bg-gray-50 focus:outline-none {}",
408 if theme() == "dark" {
409 "bg-blue-50 border-blue-200 text-blue-900"
410 } else {
411 "bg-white border-gray-200 text-gray-900"
412 }
413 ),
414 input {
415 r#type: "radio",
416 name: "theme",
417 value: "dark",
418 class: "sr-only",
419 checked: theme() == "dark",
420 onchange: move |_| theme.set("dark".to_string())
421 }
422 span { "🌙 Dark" }
423 }
424
425 // Auto theme
426 label {
427 class: format!(
428 "cursor-pointer relative flex items-center justify-center rounded-md border py-3 px-3 text-sm font-medium uppercase hover:bg-gray-50 focus:outline-none {}",
429 if theme() == "auto" {
430 "bg-blue-50 border-blue-200 text-blue-900"
431 } else {
432 "bg-white border-gray-200 text-gray-900"
433 }
434 ),
435 input {
436 r#type: "radio",
437 name: "theme",
438 value: "auto",
439 class: "sr-only",
440 checked: theme() == "auto",
441 onchange: move |_| theme.set("auto".to_string())
442 }
443 span { "🔄 Auto" }
444 }
445 }
446 }
447
448 // Interface options
449 div {
450 class: "space-y-4",
451
452 // Sidebar collapsed by default
453 div {
454 class: "flex items-center justify-between",
455 div {
456 label {
457 class: "text-sm font-medium text-gray-700",
458 "Collapse sidebar by default"
459 }
460 p {
461 class: "text-sm text-gray-500",
462 "Start with a collapsed sidebar for more screen space"
463 }
464 }
465 button {
466 r#type: "button",
467 class: format!(
468 "relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 {}",
469 if sidebar_collapsed() { "bg-blue-600" } else { "bg-gray-200" }
470 ),
471 onclick: move |_| sidebar_collapsed.set(!sidebar_collapsed()),
472 span {
473 class: format!(
474 "pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200 {}",
475 if sidebar_collapsed() { "translate-x-5" } else { "translate-x-0" }
476 )
477 }
478 }
479 }
480
481 // Compact mode
482 div {
483 class: "flex items-center justify-between",
484 div {
485 label {
486 class: "text-sm font-medium text-gray-700",
487 "Compact mode"
488 }
489 p {
490 class: "text-sm text-gray-500",
491 "Reduce spacing and padding for denser layouts"
492 }
493 }
494 button {
495 r#type: "button",
496 class: format!(
497 "relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 {}",
498 if compact_mode() { "bg-blue-600" } else { "bg-gray-200" }
499 ),
500 onclick: move |_| compact_mode.set(!compact_mode()),
501 span {
502 class: format!(
503 "pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200 {}",
504 if compact_mode() { "translate-x-5" } else { "translate-x-0" }
505 )
506 }
507 }
508 }
509
510 // Animations
511 div {
512 class: "flex items-center justify-between",
513 div {
514 label {
515 class: "text-sm font-medium text-gray-700",
516 "Enable animations"
517 }
518 p {
519 class: "text-sm text-gray-500",
520 "Use animations and transitions for smoother interactions"
521 }
522 }
523 button {
524 r#type: "button",
525 class: format!(
526 "relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 {}",
527 if animations() { "bg-blue-600" } else { "bg-gray-200" }
528 ),
529 onclick: move |_| animations.set(!animations()),
530 span {
531 class: format!(
532 "pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200 {}",
533 if animations() { "translate-x-5" } else { "translate-x-0" }
534 )
535 }
536 }
537 }
538 }
539 }
540 }
541 }
542 }
543 }
544 }
545}
546
547/// Notification settings section
548#[component]
549fn NotificationSettings() -> Element {
550 let mut email_notifications = use_signal(|| true);
551 let mut push_notifications = use_signal(|| false);
552 let mut desktop_notifications = use_signal(|| true);
553 let mut sound_enabled = use_signal(|| false);
554
555 rsx! {
556 div {
557 class: "space-y-6",
558
559 div {
560 class: "bg-white shadow px-4 py-5 sm:rounded-lg sm:p-6",
561 div {
562 class: "md:grid md:grid-cols-3 md:gap-6",
563 div {
564 class: "md:col-span-1",
565 h3 {
566 class: "text-lg font-medium leading-6 text-gray-900",
567 "Notifications"
568 }
569 p {
570 class: "mt-1 text-sm text-gray-500",
571 "Choose how you want to be notified about updates and events."
572 }
573 }
574 div {
575 class: "mt-5 md:mt-0 md:col-span-2",
576 div {
577 class: "space-y-6",
578
579 // Email notifications
580 div {
581 class: "flex items-center justify-between",
582 div {
583 label {
584 class: "text-sm font-medium text-gray-700",
585 "Email notifications"
586 }
587 p {
588 class: "text-sm text-gray-500",
589 "Receive important updates via email"
590 }
591 }
592 button {
593 r#type: "button",
594 class: format!(
595 "relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 {}",
596 if email_notifications() { "bg-blue-600" } else { "bg-gray-200" }
597 ),
598 onclick: move |_| email_notifications.set(!email_notifications()),
599 span {
600 class: format!(
601 "pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200 {}",
602 if email_notifications() { "translate-x-5" } else { "translate-x-0" }
603 )
604 }
605 }
606 }
607
608 // Push notifications
609 div {
610 class: "flex items-center justify-between",
611 div {
612 label {
613 class: "text-sm font-medium text-gray-700",
614 "Push notifications"
615 }
616 p {
617 class: "text-sm text-gray-500",
618 "Show notifications in your browser"
619 }
620 }
621 button {
622 r#type: "button",
623 class: format!(
624 "relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 {}",
625 if push_notifications() { "bg-blue-600" } else { "bg-gray-200" }
626 ),
627 onclick: move |_| push_notifications.set(!push_notifications()),
628 span {
629 class: format!(
630 "pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200 {}",
631 if push_notifications() { "translate-x-5" } else { "translate-x-0" }
632 )
633 }
634 }
635 }
636
637 // Desktop notifications
638 div {
639 class: "flex items-center justify-between",
640 div {
641 label {
642 class: "text-sm font-medium text-gray-700",
643 "Desktop notifications"
644 }
645 p {
646 class: "text-sm text-gray-500",
647 "Show system notifications on your desktop"
648 }
649 }
650 button {
651 r#type: "button",
652 class: format!(
653 "relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 {}",
654 if desktop_notifications() { "bg-blue-600" } else { "bg-gray-200" }
655 ),
656 onclick: move |_| desktop_notifications.set(!desktop_notifications()),
657 span {
658 class: format!(
659 "pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200 {}",
660 if desktop_notifications() { "translate-x-5" } else { "translate-x-0" }
661 )
662 }
663 }
664 }
665
666 // Sound notifications
667 div {
668 class: "flex items-center justify-between",
669 div {
670 label {
671 class: "text-sm font-medium text-gray-700",
672 "Sound notifications"
673 }
674 p {
675 class: "text-sm text-gray-500",
676 "Play sounds for notifications"
677 }
678 }
679 button {
680 r#type: "button",
681 class: format!(
682 "relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 {}",
683 if sound_enabled() { "bg-blue-600" } else { "bg-gray-200" }
684 ),
685 onclick: move |_| sound_enabled.set(!sound_enabled()),
686 span {
687 class: format!(
688 "pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200 {}",
689 if sound_enabled() { "translate-x-5" } else { "translate-x-0" }
690 )
691 }
692 }
693 }
694 }
695 }
696 }
697 }
698 }
699 }
700}
701
702/// Security settings section
703#[component]
704fn SecuritySettings() -> Element {
705 rsx! {
706 div {
707 class: "space-y-6",
708
709 div {
710 class: "bg-white shadow px-4 py-5 sm:rounded-lg sm:p-6",
711 div {
712 class: "md:grid md:grid-cols-3 md:gap-6",
713 div {
714 class: "md:col-span-1",
715 h3 {
716 class: "text-lg font-medium leading-6 text-gray-900",
717 "Security"
718 }
719 p {
720 class: "mt-1 text-sm text-gray-500",
721 "Manage your account security settings and preferences."
722 }
723 }
724 div {
725 class: "mt-5 md:mt-0 md:col-span-2",
726 div {
727 class: "space-y-6",
728
729 // Change password
730 div {
731 class: "flex items-center justify-between py-4 border-b border-gray-200",
732 div {
733 h4 {
734 class: "text-sm font-medium text-gray-900",
735 "Password"
736 }
737 p {
738 class: "text-sm text-gray-500",
739 "Last changed 3 months ago"
740 }
741 }
742 button {
743 r#type: "button",
744 class: "bg-white border border-gray-300 rounded-md shadow-sm py-2 px-3 text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500",
745 "Change Password"
746 }
747 }
748
749 // Two-factor authentication
750 div {
751 class: "flex items-center justify-between py-4 border-b border-gray-200",
752 div {
753 h4 {
754 class: "text-sm font-medium text-gray-900",
755 "Two-Factor Authentication"
756 }
757 p {
758 class: "text-sm text-gray-500",
759 "Add an extra layer of security to your account"
760 }
761 }
762 button {
763 r#type: "button",
764 class: "bg-blue-600 border border-transparent rounded-md shadow-sm py-2 px-3 text-sm leading-4 font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500",
765 "Enable 2FA"
766 }
767 }
768
769 // Session management
770 div {
771 class: "flex items-center justify-between py-4 border-b border-gray-200",
772 div {
773 h4 {
774 class: "text-sm font-medium text-gray-900",
775 "Active Sessions"
776 }
777 p {
778 class: "text-sm text-gray-500",
779 "Manage devices where you're signed in"
780 }
781 }
782 button {
783 r#type: "button",
784 class: "bg-white border border-gray-300 rounded-md shadow-sm py-2 px-3 text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500",
785 "Manage Sessions"
786 }
787 }
788
789 // Account deletion
790 div {
791 class: "pt-4",
792 div {
793 h4 {
794 class: "text-sm font-medium text-red-900",
795 "Danger Zone"
796 }
797 p {
798 class: "text-sm text-red-600 mt-1",
799 "Permanently delete your account and all associated data. This action cannot be undone."
800 }
801 button {
802 r#type: "button",
803 class: "mt-3 bg-red-600 border border-transparent rounded-md shadow-sm py-2 px-3 text-sm leading-4 font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500",
804 "Delete Account"
805 }
806 }
807 }
808 }
809 }
810 }
811 }
812 }
813 }
814}
815
816/// System settings section
817#[component]
818fn SystemSettings() -> Element {
819 let build = option_env!("BUILD_HASH").unwrap_or("dev");
820
821 rsx! {
822 div {
823 class: "space-y-6",
824
825 div {
826 class: "bg-white shadow px-4 py-5 sm:rounded-lg sm:p-6",
827 div {
828 class: "md:grid md:grid-cols-3 md:gap-6",
829 div {
830 class: "md:col-span-1",
831 h3 {
832 class: "text-lg font-medium leading-6 text-gray-900",
833 "System"
834 }
835 p {
836 class: "mt-1 text-sm text-gray-500",
837 "System-level settings and maintenance options."
838 }
839 }
840 div {
841 class: "mt-5 md:mt-0 md:col-span-2",
842 div {
843 class: "space-y-6",
844
845 // Cache management
846 div {
847 class: "flex items-center justify-between py-4 border-b border-gray-200",
848 div {
849 h4 {
850 class: "text-sm font-medium text-gray-900",
851 "Cache"
852 }
853 p {
854 class: "text-sm text-gray-500",
855 "Clear application cache to free up space"
856 }
857 }
858 button {
859 r#type: "button",
860 class: "bg-white border border-gray-300 rounded-md shadow-sm py-2 px-3 text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500",
861 "Clear Cache"
862 }
863 }
864
865 // Data export
866 div {
867 class: "flex items-center justify-between py-4 border-b border-gray-200",
868 div {
869 h4 {
870 class: "text-sm font-medium text-gray-900",
871 "Data Export"
872 }
873 p {
874 class: "text-sm text-gray-500",
875 "Download a copy of your data"
876 }
877 }
878 button {
879 r#type: "button",
880 class: "bg-blue-600 border border-transparent rounded-md shadow-sm py-2 px-3 text-sm leading-4 font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500",
881 "Export Data"
882 }
883 }
884
885 // System logs
886 div {
887 class: "flex items-center justify-between py-4 border-b border-gray-200",
888 div {
889 h4 {
890 class: "text-sm font-medium text-gray-900",
891 "System Logs"
892 }
893 p {
894 class: "text-sm text-gray-500",
895 "View and download system log files"
896 }
897 }
898 button {
899 r#type: "button",
900 class: "bg-white border border-gray-300 rounded-md shadow-sm py-2 px-3 text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500",
901 "View Logs"
902 }
903 }
904
905 // System information
906 div {
907 class: "pt-4",
908 div {
909 class: "bg-gray-50 rounded-lg p-4",
910 h4 {
911 class: "text-sm font-medium text-gray-900 mb-3",
912 "System Information"
913 }
914 dl {
915 class: "grid grid-cols-1 gap-x-4 gap-y-2 sm:grid-cols-2",
916 div {
917 dt {
918 class: "text-sm font-medium text-gray-500",
919 "Version"
920 }
921 dd {
922 class: "text-sm text-gray-900",
923 "{crate::VERSION}"
924 }
925 }
926 div {
927 dt {
928 class: "text-sm font-medium text-gray-500",
929 "Platform"
930 }
931 dd {
932 class: "text-sm text-gray-900",
933 "Web (WASM)"
934 }
935 }
936 div {
937 dt {
938 class: "text-sm font-medium text-gray-500",
939 "Build"
940 }
941 dd {
942 class: "text-sm text-gray-900",
943 "{build}"
944 }
945 }
946 div {
947 dt {
948 class: "text-sm font-medium text-gray-500",
949 "User Agent"
950 }
951 dd {
952 class: "text-sm text-gray-900",
953 "Qorzen Application"
954 }
955 }
956 }
957 }
958 }
959 }
960 }
961 }
962 }
963 }
964 }
965}
966
967/// About section
968#[component]
969fn AboutSettings() -> Element {
970 rsx! {
971 div {
972 class: "space-y-6",
973
974 div {
975 class: "bg-white shadow px-4 py-5 sm:rounded-lg sm:p-6",
976 div {
977 class: "text-center",
978 div {
979 class: "mx-auto h-16 w-16 bg-blue-600 rounded-xl flex items-center justify-center mb-4",
980 span {
981 class: "text-white font-bold text-2xl",
982 "Q"
983 }
984 }
985 h2 {
986 class: "text-2xl font-bold text-gray-900",
987 "Qorzen"
988 }
989 p {
990 class: "text-sm text-gray-500 mt-1",
991 "Version {crate::VERSION}"
992 }
993 p {
994 class: "text-gray-600 mt-4 max-w-2xl mx-auto",
995 "A modular, cross-platform application framework built with Rust and Dioxus.
996 Designed for modern development workflows with extensibility through plugins."
997 }
998
999 div {
1000 class: "mt-8 flex justify-center space-x-6",
1001 a {
1002 href: "https://github.com/qorzen/qorzen-oxide",
1003 target: "_blank",
1004 rel: "noopener noreferrer",
1005 class: "text-gray-400 hover:text-gray-500",
1006 span {
1007 class: "sr-only",
1008 "GitHub"
1009 }
1010 "🐙 GitHub"
1011 }
1012 a {
1013 href: "https://docs.qorzen.com",
1014 target: "_blank",
1015 rel: "noopener noreferrer",
1016 class: "text-gray-400 hover:text-gray-500",
1017 "📚 Documentation"
1018 }
1019 a {
1020 href: "mailto:support@qorzen.com",
1021 class: "text-gray-400 hover:text-gray-500",
1022 "📧 Support"
1023 }
1024 }
1025
1026 div {
1027 class: "mt-8 pt-8 border-t border-gray-200",
1028 p {
1029 class: "text-sm text-gray-500",
1030 "© 2024 Qorzen. Built with ❤️ and 🦀"
1031 }
1032 p {
1033 class: "text-xs text-gray-400 mt-2",
1034 "Licensed under the MIT License"
1035 }
1036 }
1037 }
1038 }
1039 }
1040 }
1041}
1042
1043#[cfg(test)]
1044mod tests {
1045 use super::*;
1046
1047 #[test]
1048 fn test_settings_component_creation() {
1049 let _settings = rsx! { Settings {} };
1050 }
1051
1052 #[test]
1053 fn test_general_settings_creation() {
1054 let _general = rsx! { GeneralSettings {} };
1055 }
1056
1057 #[test]
1058 fn test_appearance_settings_creation() {
1059 let _appearance = rsx! { AppearanceSettings {} };
1060 }
1061}