Skip to main content

rustyclaw_tui/components/
auth_dialog.rs

1// ── Auth dialog — TOTP code entry overlay ───────────────────────────────────
2
3use crate::theme;
4use iocraft::prelude::*;
5
6#[derive(Default, Props)]
7pub struct AuthDialogProps {
8    /// The digits entered so far (0–6 characters).
9    pub code: String,
10    /// Optional error/retry message to display.
11    pub error: String,
12}
13
14#[component]
15pub fn AuthDialog(props: &AuthDialogProps) -> impl Into<AnyElement<'static>> {
16    // Build the display: show typed digits + placeholder dots
17    let typed = &props.code;
18    let remaining = 6usize.saturating_sub(typed.len());
19    let display = format!("{}{}", typed, "·".repeat(remaining),);
20
21    let has_error = !props.error.is_empty();
22
23    element! {
24        // Full-screen overlay with semi-transparent feel
25        View(
26            width: 100pct,
27            height: 100pct,
28            justify_content: JustifyContent::Center,
29            align_items: AlignItems::Center,
30        ) {
31            // Dialog box
32            View(
33                width: 48,
34                flex_direction: FlexDirection::Column,
35                border_style: BorderStyle::Round,
36                border_color: theme::ACCENT_BRIGHT,
37                background_color: theme::BG_SURFACE,
38                padding_left: 2,
39                padding_right: 2,
40                padding_top: 1,
41                padding_bottom: 1,
42            ) {
43                // Title
44                Text(
45                    content: "🔑 Gateway Authentication",
46                    color: theme::ACCENT_BRIGHT,
47                    weight: Weight::Bold,
48                )
49
50                // Spacer
51                View(height: 1)
52
53                // Label
54                Text(
55                    content: "Enter your 6-digit TOTP code:",
56                    color: theme::TEXT,
57                )
58
59                // Spacer
60                View(height: 1)
61
62                // Code display
63                View(
64                    flex_direction: FlexDirection::Row,
65                    justify_content: JustifyContent::Center,
66                ) {
67                    Text(
68                        content: format!("  {}  ", display),
69                        color: theme::ACCENT_BRIGHT,
70                        weight: Weight::Bold,
71                    )
72                }
73
74                // Error message (if any)
75                #(if has_error {
76                    element! {
77                        View(margin_top: 1) {
78                            Text(content: props.error.clone(), color: theme::ERROR)
79                        }
80                    }.into_any()
81                } else {
82                    element! {
83                        View()
84                    }.into_any()
85                })
86
87                // Spacer
88                View(height: 1)
89
90                // Hint
91                Text(
92                    content: "Enter ↩ submit  ·  Esc cancel",
93                    color: theme::MUTED,
94                )
95            }
96        }
97    }
98}