/ web / src / pages / panels / flash_panel / mod.rs
mod.rs
 1  mod bridge;
 2  mod components;
 3  mod hooks;
 4  mod state;
 5  
 6  use dioxus::prelude::*;
 7  use components::*;
 8  use hooks::use_flash_controller;
 9  use ui::components::button::{Button, ButtonVariant};
10  
11  #[component]
12  pub fn FlashPanel() -> Element {
13      let ctrl = use_flash_controller();
14      let device = ctrl.device;
15      let chip = ctrl.chip;
16  
17      rsx! {
18          section { id: "flash-panel", class: "panel-shell-strong p-4",
19  
20              // ── Title ──
21              div { class: "flex items-center gap-2 flex-wrap mb-3",
22                  h2 { class: "text-xl font-semibold", "Firmware Update" }
23                  if *device.is_connected.read() {
24                      span { class: "text-xs font-mono text-muted-foreground", "{chip.chip_name}" }
25                      if !chip.chip_mac.read().is_empty() {
26                          span { class: "text-[10px] font-mono text-muted-foreground/70", "{chip.chip_mac}" }
27                      }
28                  }
29              }
30  
31              // ── Chip info ──
32              if *device.is_connected.read() && !chip.chip_description.read().is_empty() {
33                  div { class: "text-xs text-muted-foreground mb-2",
34                      span { "{chip.chip_description}" }
35                      if !chip.chip_features.read().is_empty() {
36                          span { class: "ml-2 text-muted-foreground/60",
37                              "({chip.chip_features.read().join(\", \")})"
38                          }
39                      }
40                  }
41              }
42  
43              // ── Connected controls ──
44              if *device.is_connected.read() {
45                  Button {
46                      class: "w-full py-2 border-destructive/50 text-destructive font-semibold hover:bg-destructive/10 mb-3".to_string(),
47                      variant: ButtonVariant::Destructive,
48                      on_click: move |_| ctrl.disconnect(),
49                      icon_left: rsx! { lucide_dioxus::Plug { class: "w-3.5 h-3.5" } },
50                      "Disconnect"
51                  }
52  
53                  div { class: "grid grid-cols-1 lg:grid-cols-2 gap-3 mb-3",
54                      div { class: "flex flex-col gap-3",
55                          ConfigSection { config: ctrl.config, chip: ctrl.chip }
56                          WiFiSection { config: ctrl.config }
57                      }
58                      FirmwareSection { controller: ctrl, config: ctrl.config, chip: ctrl.chip }
59                  }
60  
61                  ActionRow { controller: ctrl }
62                  ProgressBar { progress: ctrl.firmware.progress }
63              }
64  
65              // ── Connect button ──
66              if !*device.is_connected.read() {
67                  Button {
68                      class: "gold-button-outline text-sm w-full justify-center py-3".to_string(),
69                      variant: ButtonVariant::Outline,
70                      disabled: *device.connecting.read(),
71                      loading: *device.connecting.read(),
72                      on_click: move |_| ctrl.connect(),
73                      icon_left: if !*device.connecting.read() {
74                          Some(rsx! { lucide_dioxus::Plug { class: "w-4 h-4" } })
75                      } else {
76                          None
77                      },
78                      if *device.connecting.read() { "Connecting..." } else { "Connect" }
79                  }
80              }
81  
82              // ── Terminal ──
83              div {
84                  id: "flash-monitor-term",
85                  class: if *device.is_connected.read() { "h-[400px] bg-[#0a0a0c] border border-border rounded-lg overflow-hidden mt-3" } else { "hidden" },
86              }
87          }
88      }
89  }