feat(nouser-explorer): integración al stack yahweh themed

Iter 10. nouser-explorer (paralela a nakui-explorer pero para ver
Mónadas via daemon nouser) tenía colors hardcoded idénticos al
patrón previo. Aplico el mismo refactor: theme global instalado,
chrome a slots, widgets compartidos.

- Nuevas deps: yahweh-theme + 3 widgets (banner, card,
  theme-switcher).
- main() instala Theme::install_default.
- render: 4 vars rgb() chrome → theme slots.
- Header: flex_row + theme switcher a la derecha (mismo pattern
  que nakui-explorer).
- error_banner: div hardcoded → banner_themed(Error).
- 2 cards (Engine/Monad): div().flex_col().p().bg().rounded()...
  → card_themed(cx).border_l_4().border_color(accent).
- Accents semánticos (engine cyan, data purple) quedan locales
  como señales de dominio.

Las dos apps explorer del repo ahora comparten paleta themed +
switcher común.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-05-10 11:09:33 +00:00
parent ea074d7d57
commit 2f426b0171
4 changed files with 72 additions and 28 deletions
+4
View File
@@ -9,6 +9,10 @@ description = "Explorador GPUI de Mónadas: panel que descubre al daemon nouser
brahman-card = { path = "../../core/brahman-card" }
brahman-sidecar = { path = "../../shared/brahman-sidecar" }
nouser-card = { path = "../../modules/nouser/card" }
yahweh-theme = { path = "../../modules/ui_engine/libs/theme" }
yahweh-widget-banner = { path = "../../modules/ui_engine/widgets/banner" }
yahweh-widget-card = { path = "../../modules/ui_engine/widgets/card" }
yahweh-widget-theme-switcher = { path = "../../modules/ui_engine/widgets/theme-switcher" }
gpui = { workspace = true }
[[bin]]
+27 -28
View File
@@ -29,6 +29,10 @@ use gpui::{
use nouser_card::query::client as query_client;
use nouser_card::query::{transport, ListMonadsResponse, FLOW_MONAD_LIST, FLOW_TYPE_NAME};
use nouser_card::Lens;
use yahweh_theme::Theme;
use yahweh_widget_banner::{banner_themed, Banner};
use yahweh_widget_card::card_themed;
use yahweh_widget_theme_switcher::theme_switcher;
const REFRESH_INTERVAL: Duration = Duration::from_secs(2);
const DISCOVERY_TIMEOUT: Duration = Duration::from_secs(3);
@@ -36,6 +40,9 @@ const QUERY_TIMEOUT: Duration = Duration::from_secs(2);
fn main() {
Application::new().run(|cx: &mut App| {
// Theme global instalado al boot — los widgets themed lo
// requieren y unifica el chrome del app.
Theme::install_default(cx);
let bounds = Bounds::centered(None, gpui::size(px(900.), px(640.)), cx);
cx.open_window(
WindowOptions {
@@ -192,11 +199,14 @@ fn discover_via_broker() -> Result<PathBuf, ConsumerError> {
}
impl Render for Explorer {
fn render(&mut self, _w: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
let bg = rgb(0x14171c);
let card_bg = rgb(0x1d2128);
let text_dim = rgb(0x9ba1ad);
let text = rgb(0xe6e8ec);
fn render(&mut self, _w: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
// Chrome viene del Theme global; los acentos por kind
// (engine cyan, data purple) son señales semánticas del
// dominio nouser y se mantienen locales.
let theme = Theme::global(cx).clone();
let bg = theme.bg_app.clone();
let text = theme.fg_text;
let text_dim = theme.fg_muted;
let accent_engine = rgb(0x88c0d0);
let accent_data = rgb(0xb48ead);
@@ -216,24 +226,27 @@ impl Render for Explorer {
_ => "Buscando daemon nouser vía brahman-broker…".to_string(),
};
// Header con título a la izquierda + theme switcher a la
// derecha (mismo pattern que nakui-explorer).
let header = div()
.flex()
.flex_row()
.items_center()
.px(px(16.))
.py(px(12.))
.bg(card_bg)
.bg(theme.bg_panel.clone())
.border_b_1()
.border_color(rgb(0x2a2f38))
.border_color(theme.border)
.text_color(text)
.text_size(px(14.))
.child(header_text);
.child(div().flex_grow().child(header_text))
.child(theme_switcher(cx));
let error_banner = self.error.as_ref().map(|e| {
div()
banner_themed(cx, Banner::Error, e.clone())
.px(px(16.))
.py(px(8.))
.bg(rgb(0x4a2020))
.text_color(rgb(0xffd0d0))
.text_size(px(12.))
.child(e.clone())
});
let cards: Vec<gpui::AnyElement> = match &self.snapshot {
@@ -243,16 +256,9 @@ impl Render for Explorer {
// Engine card primero — el "ser" que owns las Mónadas.
out.push(
div()
.flex()
.flex_col()
.p(px(12.))
.mb(px(8.))
.bg(card_bg)
.rounded(px(6.))
card_themed(cx)
.border_l_4()
.border_color(accent_engine)
.gap(px(2.))
.child(
div()
.flex()
@@ -305,16 +311,9 @@ impl Render for Explorer {
.map(|m| format!("model: {m}"));
out.push(
div()
.flex()
.flex_col()
.p(px(12.))
.mb(px(8.))
.bg(card_bg)
.rounded(px(6.))
card_themed(cx)
.border_l_4()
.border_color(accent_data)
.gap(px(2.))
.child(
div()
.flex()