Skip to main content

gpui-patterns

Common UI patterns and advanced techniques for GPUI applications. Use when implementing modals, lists, forms, state sharing, or complex component compositions.

Informações da origem

Repositório
zerx-lab/rmx
Última atividade na origem
5 de fevereiro de 2026 às 09:49
Idioma detectado do SKILL.md
inglês
Estrelas
70
Forks
2

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
gpui-patterns
description
Common UI patterns and advanced techniques for GPUI applications. Use when implementing modals, lists, forms, state sharing, or complex component compositions.
# GPUI Patterns This skill provides common UI patterns and advanced techniques for GPUI applications. ## Modal/Overlay Pattern ### Basic Modal ```rust use gpui::*; struct Modal { is_open: bool, content: SharedString, } impl Render for Modal { fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { div() .when(self.is_open, |this| { this.absolute() .inset_0() .flex() .items_center() .justify_center() .bg(rgba(0, 0, 0, 0.5)) .on_click(cx.listener(|this, _event, _window, cx| { this.close(cx); })) .child( div() .p_6() .bg(rgb(0x1a1a1a)) .rounded_lg() .min_w(px(300.0)) .child(self.content.clone()) ) }) } } impl Modal { fn open(&mut self, content: impl Into<SharedString>, cx: &mut Context<Self>) { self.is_open = true; self.content = content.into(); cx.notify(); } fn close(&mut self, cx: &mut Context<Self>) { self.is_open = false; cx.notify(); } } ``` ## List Pattern ### Dynamic List Rendering ```rust struct ListView { items: Vec<String>, } impl Render for ListView { fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { div() .v_flex() .gap_2() .children( self.items.iter().enumerate().map(|(index, item)| { self.render_item(index, item, cx) }) ) } } impl ListView { fn render_item( &self, index: usize, item: &str, cx: &Context<Self>, ) -> impl IntoElement { div() .p_3() .bg(rgb(0x1a1a1a)) .rounded(px(4.0)) .flex() .justify_between() .child(format!("{}. {}", index + 1, item)) .child( div() .px_3() .py_1() .bg(rgb(0xef4444)) .rounded(px(4.0)) .cursor_pointer() .child("Delete") .on_click(cx.listener(move |this, _event, _window, cx| { this.remove_item(index, cx); })) ) } fn remove_item(&mut self, index: usize, cx: &mut Context<Self>) { if index < self.items.len() { self.items.remove(index); cx.notify(); } } } ``` ## Form Pattern ### Form with Validation ```rust struct LoginForm { username: SharedString, password: SharedString, error: Option<SharedString>, } impl Render for LoginForm { fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { div() .v_flex() .gap_4() .p_6() .when_some(self.error.clone(), |this, error| { this.child( div() .p_3() .bg(rgb(0xef4444)) .rounded(px(4.0)) .child(error) ) }) .child(self.render_input("Username", &self.username, cx)) .child(self.render_input("Password", &self.password, cx)) .child( div() .px_6() .py_3() .bg(rgb(0x3b82f6)) .rounded(px(6.0)) .cursor_pointer() .child("Login") .on_click(cx.listener(|this, _event, _window, cx| { this.submit(cx); })) ) } } impl LoginForm { fn render_input( &self, label: &str, value: &SharedString, _cx: &Context<Self>, ) -> impl IntoElement { div() .v_flex() .gap_1() .child( div().text_sm().child(label) ) .child( div() .w_full() .px_3() .py_2() .bg(rgb(0x1a1a1a)) .border_1() .border_color(rgb(0x4a4a4a)) .rounded(px(4.0)) .child(value.clone()) ) } fn submit(&mut self, cx: &mut Context<Self>) { if self.username.is_empty() || self.password.is_empty() { self.error = Some("Please fill in all fields".into()); cx.notify(); return; } self.error = None; // Handle login... } } ``` ## Global State Pattern ### Shared Application State ```rust #[derive(Clone)] struct AppState { user: Option<String>, theme: String, } // Set global state fn init_app_state(cx: &mut App) { let state = AppState { user: None, theme: "dark".to_string(), }; cx.set_global(state); } // Access global state fn use_app_state(cx: &App) -> AppState { cx.global::<AppState>().clone() } // Update global state fn set_user(cx: &mut App, user: String) { let mut state = cx.global::<AppState>().clone(); state.user = Some(user); cx.set_global(state); } ``` ## Parent-Child Communication ### Child Notifying Parent ```rust #[derive(Clone, Debug)] enum ChildEvent { ValueChanged(i32), } impl EventEmitter<ChildEvent> for Child {} struct Parent { child: Entity<Child>, _subscription: Subscription, } impl Parent { fn new(cx: &mut Context<Self>) -> Self { let child = cx.new(|_| Child::new()); let subscription = cx.subscribe(&child, |this, _child, event, cx| { match event { ChildEvent::ValueChanged(value) => { println!("Child value changed to: {}", value); cx.notify(); } } }); Self { child, _subscription: subscription, } } } struct Child { value: i32, } impl Child { fn new() -> Self { Self { value: 0 } } fn set_value(&mut self, value: i32, cx: &mut Context<Self>) { self.value = value; cx.emit(ChildEvent::ValueChanged(value)); cx.notify(); } } ``` ## Tab Navigation ### Tab View Pattern ```rust #[derive(Clone, Copy, PartialEq)] enum Tab { Home, Settings, Profile, } struct TabView { active_tab: Tab, } impl Render for TabView { fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { div() .v_flex() .size_full() .child(self.render_tabs(cx)) .child(self.render_content()) } } impl TabView { fn render_tabs(&self, cx: &Context<Self>) -> impl IntoElement { div() .h_flex() .gap_2() .p_2() .bg(rgb(0x1a1a1a)) .child(self.render_tab("Home", Tab::Home, cx)) .child(self.render_tab("Settings", Tab::Settings, cx)) .child(self.render_tab("Profile", Tab::Profile, cx)) } fn render_tab(&self, label: &str, tab: Tab, cx: &Context<Self>) -> impl IntoElement { let is_active = self.active_tab == tab; div() .px_4() .py_2() .rounded(px(4.0)) .cursor_pointer() .bg(if is_active { rgb(0x3b82f6) } else { rgb(0x2a2a2a) }) .child(label) .on_click(cx.listener(move |this, _event, _window, cx| { this.active_tab = tab; cx.notify(); })) } fn render_content(&self) -> impl IntoElement { match self.active_tab { Tab::Home => div().child("Home Content"), Tab::Settings => div().child("Settings Content"), Tab::Profile => div().child("Profile Content"), } } } ``` ## Loading State Pattern ### Async Data Loading ```rust enum LoadState<T> { Idle, Loading, Loaded(T), Error(String), } struct DataView { state: LoadState<Vec<String>>, } impl Render for DataView { fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { match &self.state { LoadState::Idle => { div().child("Click to load") .on_click(cx.listener(|this, _event, _window, cx| { this.load_data(cx); })) } LoadState::Loading => { div().child("Loading...") } LoadState::Loaded(items) => { div() .v_flex() .gap_2() .children(items.iter().map(|item| { div().child(item.clone()) })) } LoadState::Error(error) => { div() .p_3() .bg(rgb(0xef4444)) .child(format!("Error: {}", error)) } } } } impl DataView { fn load_data(&mut self, cx: &mut Context<Self>) { self.state = LoadState::Loading; cx.notify(); cx.spawn(async move |this, cx| { match fetch_data().await { Ok(data) => { this.update(&mut *cx, |view, cx| { view.state = LoadState::Loaded(data); cx.notify(); })?; } Err(e) => { this.update(&mut *cx, |view, cx| { view.state = LoadState::Error(e.to_string()); cx.notify(); })?; } } Ok(()) }).detach(); } } async fn fetch_data() -> Result<Vec<String>, anyhow::Error> { // Simulate API call tokio::time::sleep(Duration::from_secs(1)).await; Ok(vec!["Item 1".to_string(), "Item 2".to_string()]) } ``` ## Dropdown Pattern ```rust struct Dropdown {
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub