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:
Hibryda 2026-03-19 06:05:58 +01:00
parent 90c7315336
commit f3d2ca78ba
34 changed files with 17467 additions and 0 deletions

View file

@ -0,0 +1,85 @@
/// StatusBar — bottom bar showing agent fleet state, cost, and attention.
///
/// Mirrors the Svelte app's StatusBar.svelte (Mission Control bar).
use dioxus::prelude::*;
#[derive(Clone, PartialEq)]
pub struct FleetState {
pub running: usize,
pub idle: usize,
pub stalled: usize,
pub total_cost: f64,
pub total_tokens: u64,
pub project_count: usize,
}
#[component]
pub fn StatusBar(fleet: FleetState) -> Element {
rsx! {
div { class: "status-bar",
// Left section: agent counts
div { class: "status-bar-left",
// Running
div { class: "status-item",
div {
class: "status-dot running",
style: "width: 6px; height: 6px; border-radius: 50%; display: inline-block;",
}
span { class: "status-count running", "{fleet.running}" }
span { "running" }
}
// Idle
div { class: "status-item",
div {
class: "status-dot idle",
style: "width: 6px; height: 6px; border-radius: 50%; display: inline-block;",
}
span { class: "status-count idle", "{fleet.idle}" }
span { "idle" }
}
// Stalled
if fleet.stalled > 0 {
div { class: "status-item",
div {
class: "status-dot stalled",
style: "width: 6px; height: 6px; border-radius: 50%; display: inline-block;",
}
span { class: "status-count stalled", "{fleet.stalled}" }
span { "stalled" }
}
}
// Separator
span { style: "color: var(--ctp-surface1);", "|" }
// Projects
div { class: "status-item",
span { "{fleet.project_count} projects" }
}
}
// Right section: cost + tokens
div { class: "status-bar-right",
div { class: "status-item",
span { class: "status-cost", "${fleet.total_cost:.4}" }
}
div { class: "status-item",
span { "{format_tokens(fleet.total_tokens)} tokens" }
}
}
}
}
}
fn format_tokens(tokens: u64) -> String {
if tokens >= 1_000_000 {
format!("{:.1}M", tokens as f64 / 1_000_000.0)
} else if tokens >= 1_000 {
format!("{:.1}K", tokens as f64 / 1_000.0)
} else {
tokens.to_string()
}
}