feat: add Dioxus and GPUI UI prototypes for framework comparison
Dioxus (ui-dioxus/): 2,169 lines, WebView mode (same wry as Tauri), Catppuccin theme, 12 components, agor-core integration, compiles clean. Evolution path — keeps xterm.js, gradual migration from Tauri. GPUI (ui-gpui/): 2,490 lines, GPU-accelerated rendering, alacritty_terminal for native terminal, 17 files, Catppuccin palette, demo data. Revolution path — pure Rust UI, 120fps target, no WebView. Both are standalone (not in workspace), share agor-core backend. Created for side-by-side comparison to inform framework decision.
This commit is contained in:
parent
90c7315336
commit
f3d2ca78ba
34 changed files with 17467 additions and 0 deletions
136
ui-dioxus/src/main.rs
Normal file
136
ui-dioxus/src/main.rs
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/// Agent Orchestrator — Dioxus 0.7 Desktop Prototype
|
||||
///
|
||||
/// This prototype demonstrates the core Agent Orchestrator experience
|
||||
/// built with Dioxus 0.7 (desktop mode via wry/WebKit2GTK).
|
||||
///
|
||||
/// Architecture comparison vs Tauri+Svelte:
|
||||
///
|
||||
/// | Aspect | Tauri+Svelte (current) | Dioxus (this prototype) |
|
||||
/// |---------------------|-------------------------------|-------------------------------|
|
||||
/// | UI rendering | WebView (Svelte -> HTML) | WebView (RSX -> HTML) |
|
||||
/// | State management | Svelte 5 runes ($state) | Dioxus signals (use_signal) |
|
||||
/// | Backend bridge | Tauri IPC (invoke/listen) | Direct Rust (no IPC!) |
|
||||
/// | Terminal | xterm.js via WebView | xterm.js via WebView (same) |
|
||||
/// | Reactivity model | Compiler-based (Svelte 5) | Runtime signals (fine-grained)|
|
||||
/// | Component model | .svelte files (HTML+JS+CSS) | Rust functions (rsx! macro) |
|
||||
/// | Type safety | TypeScript (compile-time) | Rust (compile-time, stronger) |
|
||||
/// | Hot reload | Vite HMR | dx serve (RSX hot reload) |
|
||||
///
|
||||
/// Key advantage: no IPC serialization boundary. Backend state (PtyManager,
|
||||
/// SidecarManager) is directly accessible from UI code as typed Rust values.
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod backend;
|
||||
mod components;
|
||||
mod state;
|
||||
mod theme;
|
||||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
use components::command_palette::CommandPalette;
|
||||
use components::project_grid::ProjectGrid;
|
||||
use components::settings::SettingsPanel;
|
||||
use components::sidebar::Sidebar;
|
||||
use components::status_bar::{FleetState, StatusBar};
|
||||
use state::demo_projects;
|
||||
|
||||
fn main() {
|
||||
dioxus::LaunchBuilder::new()
|
||||
.with_cfg(dioxus::desktop::Config::new()
|
||||
.with_window(
|
||||
dioxus::desktop::WindowBuilder::new()
|
||||
.with_title("Agent Orchestrator — Dioxus Prototype")
|
||||
.with_inner_size(dioxus::desktop::LogicalSize::new(1400.0, 900.0))
|
||||
)
|
||||
.with_custom_head(format!(
|
||||
"<style>{}</style>",
|
||||
theme::generate_css()
|
||||
))
|
||||
.with_background_color((30, 30, 46, 255)) // --ctp-base
|
||||
)
|
||||
.launch(App);
|
||||
}
|
||||
|
||||
/// Root application component.
|
||||
///
|
||||
/// Layout: sidebar rail | optional drawer | project grid | status bar
|
||||
/// Same structure as the Svelte app's App.svelte.
|
||||
#[allow(non_snake_case)]
|
||||
fn App() -> Element {
|
||||
// Global UI state
|
||||
let mut settings_open = use_signal(|| false);
|
||||
let mut palette_open = use_signal(|| false);
|
||||
|
||||
// Projects — in the real app, loaded from groups.json via groups-bridge
|
||||
let projects = use_signal(|| demo_projects());
|
||||
|
||||
// Fleet state — derived from all project health stores
|
||||
let fleet = FleetState {
|
||||
running: 1,
|
||||
idle: 1,
|
||||
stalled: 0,
|
||||
total_cost: 0.1694,
|
||||
total_tokens: 48_700,
|
||||
project_count: projects.read().len(),
|
||||
};
|
||||
|
||||
// Keyboard shortcuts
|
||||
let on_keydown = move |e: KeyboardEvent| {
|
||||
let modifiers = e.modifiers();
|
||||
let is_ctrl = modifiers.ctrl();
|
||||
|
||||
match e.key() {
|
||||
// Ctrl+K: Command palette
|
||||
Key::Character(ref c) if is_ctrl && c == "k" => {
|
||||
palette_open.set(true);
|
||||
}
|
||||
// Ctrl+,: Toggle settings
|
||||
Key::Character(ref c) if is_ctrl && c == "," => {
|
||||
let current = *settings_open.read();
|
||||
settings_open.set(!current);
|
||||
}
|
||||
// Ctrl+B: Toggle sidebar drawer
|
||||
Key::Character(ref c) if is_ctrl && c == "b" => {
|
||||
let current = *settings_open.read();
|
||||
settings_open.set(!current);
|
||||
}
|
||||
// Escape: close overlays
|
||||
Key::Escape => {
|
||||
if *palette_open.read() {
|
||||
palette_open.set(false);
|
||||
} else if *settings_open.read() {
|
||||
settings_open.set(false);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
|
||||
rsx! {
|
||||
div {
|
||||
class: "app-shell",
|
||||
onkeydown: on_keydown,
|
||||
tabindex: "0",
|
||||
|
||||
// Main body: sidebar + optional drawer + workspace
|
||||
div { class: "app-body",
|
||||
// Left sidebar rail
|
||||
Sidebar { settings_open: settings_open }
|
||||
|
||||
// Optional drawer panel (settings)
|
||||
if *settings_open.read() {
|
||||
SettingsPanel {}
|
||||
}
|
||||
|
||||
// Main workspace: project grid
|
||||
ProjectGrid { projects: projects.read().clone() }
|
||||
}
|
||||
|
||||
// Bottom status bar
|
||||
StatusBar { fleet: fleet }
|
||||
|
||||
// Command palette overlay
|
||||
CommandPalette { visible: palette_open }
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue