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.

Quellinformationen

Repository
zerx-lab/rmx
Letzte Quellaktivität
5. Februar 2026 um 09:49
Erkannte Sprache von SKILL.md
Englisch
Sterne
70
Forks
2

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
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 {
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen