gpui-components

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

GPUI Components Skill

GPUI组件开发技能

Generates production-ready Rust code for GPUI desktop UI components following patterns from Zed editor and gpui-component library.
生成遵循Zed编辑器和gpui-component库模式的可用于生产环境的GPUI桌面UI组件Rust代码。

When to Use This Skill

何时使用该技能

  • Building desktop UI applications with GPUI framework
  • Creating custom components using
    RenderOnce
    or
    Render
    traits
  • Implementing themed components with
    ActiveTheme
  • Building autocomplete/completion menus
  • Creating command palettes and popup menus
  • Working with
    gpui-component
    crate
  • 使用GPUI框架构建桌面UI应用
  • 使用
    RenderOnce
    Render
    trait创建自定义组件
  • 基于
    ActiveTheme
    实现主题化组件
  • 构建自动补全菜单
  • 创建命令面板和弹出菜单
  • 使用
    gpui-component
    crate

Core GPUI Concepts

GPUI核心概念

Application Setup

应用程序设置

rust
use gpui::{Application, Window, Context, div, px, rgb};
use gpui_component::{init, Root, Theme};

fn main() {
    Application::new().run(|cx| {
        // Initialize gpui-component
        gpui_component::init(cx);
        
        cx.open_window(
            WindowOptions::default(),
            |window, cx| Root::new(MyApp::new(cx), window, cx)
        );
    });
}
rust
use gpui::{Application, Window, Context, div, px, rgb};
use gpui_component::{init, Root, Theme};

fn main() {
    Application::new().run(|cx| {
        // Initialize gpui-component
        gpui_component::init(cx);
        
        cx.open_window(
            WindowOptions::default(),
            |window, cx| Root::new(MyApp::new(cx), window, cx)
        );
    });
}

Component Patterns

组件模式

RenderOnce (Stateless)

RenderOnce(无状态)

rust
use gpui::{IntoElement, RenderOnce, Styled, div};

#[derive(IntoElement)]
pub struct MyButton {
    label: SharedString,
    variant: ButtonVariant,
}

impl RenderOnce for MyButton {
    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
        div()
            .px_3()
            .py_2()
            .bg(cx.theme().primary)
            .text_color(cx.theme().primary_foreground)
            .rounded_md()
            .child(self.label)
    }
}
rust
use gpui::{IntoElement, RenderOnce, Styled, div};

#[derive(IntoElement)]
pub struct MyButton {
    label: SharedString,
    variant: ButtonVariant,
}

impl RenderOnce for MyButton {
    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
        div()
            .px_3()
            .py_2()
            .bg(cx.theme().primary)
            .text_color(cx.theme().primary_foreground)
            .rounded_md()
            .child(self.label)
    }
}

Render with Entity (Stateful)

基于Entity的Render(有状态)

rust
use gpui::{Entity, Render, Context};

pub struct Counter {
    count: i32,
}

impl Render for Counter {
    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        div()
            .flex()
            .gap_2()
            .child(Button::new("dec").on_click(cx.listener(|this, _, _, cx| {
                this.count -= 1;
                cx.notify();
            })))
            .child(format!("Count: {}", self.count))
            .child(Button::new("inc").on_click(cx.listener(|this, _, _, cx| {
                this.count += 1;
                cx.notify();
            })))
    }
}
rust
use gpui::{Entity, Render, Context};

pub struct Counter {
    count: i32,
}

impl Render for Counter {
    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        div()
            .flex()
            .gap_2()
            .child(Button::new("dec").on_click(cx.listener(|this, _, _, cx| {
                this.count -= 1;
                cx.notify();
            })))
            .child(format!("Count: {}", self.count))
            .child(Button::new("inc").on_click(cx.listener(|this, _, _, cx| {
                this.count += 1;
                cx.notify();
            })))
    }
}

Available Components (gpui-component)

可用组件(gpui-component)

Form Components

表单组件

  • Button
    - Buttons with variants (primary, danger, ghost, link)
  • Input
    - Text input with LSP completion support
  • NumberInput
    - Numeric input with step controls
  • Checkbox
    - Checkbox with label
  • Switch
    - Toggle switch
  • Radio
    - Radio button groups
  • Select
    - Dropdown select
  • Slider
    - Range slider
  • Button
    - 包含多种变体的按钮(primary、danger、ghost、link)
  • Input
    - 支持LSP补全的文本输入框
  • NumberInput
    - 带步进控制的数字输入框
  • Checkbox
    - 带标签的复选框
  • Switch
    - 切换开关
  • Radio
    - 单选按钮组
  • Select
    - 下拉选择框
  • Slider
    - 范围滑块

Layout Components

布局组件

  • Dialog
    - Modal dialogs
  • Popover
    - Popup popovers
  • Menu
    /
    PopupMenu
    - Menus and context menus
  • Tab
    - Tab navigation
  • Accordion
    - Collapsible sections
  • Sidebar
    - Sidebar navigation
  • Dock
    - Dockable panels
  • Dialog
    - 模态对话框
  • Popover
    - 弹出式气泡框
  • Menu
    /
    PopupMenu
    - 菜单和上下文菜单
  • Tab
    - 标签页导航
  • Accordion
    - 可折叠面板
  • Sidebar
    - 侧边栏导航
  • Dock
    - 可停靠面板

Display Components

展示组件

  • Badge
    - Status badges
  • Avatar
    - User avatars
  • Icon
    - Icon display (IconName enum)
  • Label
    - Text labels
  • Tooltip
    - Tooltips
  • Notification
    - Toast notifications
  • Badge
    - 状态徽章
  • Avatar
    - 用户头像
  • Icon
    - 图标展示(IconName枚举)
  • Label
    - 文本标签
  • Tooltip
    - 提示框
  • Notification
    - 消息通知框

Data Components

数据组件

  • Table
    - Data tables
  • List
    /
    VirtualList
    - Scrollable lists
  • Tree
    - Tree view
  • Chart
    - Charts and plots
  • Table
    - 数据表格
  • List
    /
    VirtualList
    - 可滚动列表
  • Tree
    - 树形视图
  • Chart
    - 图表与绘图

Theming

主题设置

Accessing Theme

访问主题

rust
use gpui_component::ActiveTheme;

fn render(&mut self, window: &mut Window, cx: &mut App) -> impl IntoElement {
    div()
        .bg(cx.theme().background)
        .text_color(cx.theme().foreground)
        .border_1()
        .border_color(cx.theme().border)
}
rust
use gpui_component::ActiveTheme;

fn render(&mut self, window: &mut Window, cx: &mut App) -> impl IntoElement {
    div()
        .bg(cx.theme().background)
        .text_color(cx.theme().foreground)
        .border_1()
        .border_color(cx.theme().border)
}

Theme Colors

主题颜色

rust
// Background colors
cx.theme().background      // Primary background
cx.theme().secondary       // Secondary background  
cx.theme().muted          // Muted background
cx.theme().card           // Card background

// Foreground colors
cx.theme().foreground     // Primary text
cx.theme().muted_foreground // Muted text

// Semantic colors
cx.theme().primary        // Primary accent
cx.theme().destructive    // Danger/error
cx.theme().success        // Success
cx.theme().warning        // Warning

// Border colors
cx.theme().border         // Default border
cx.theme().ring           // Focus ring
rust
// Background colors
cx.theme().background      // Primary background
cx.theme().secondary       // Secondary background  
cx.theme().muted          // Muted background
cx.theme().card           // Card background

// Foreground colors
cx.theme().foreground     // Primary text
cx.theme().muted_foreground // Muted text

// Semantic colors
cx.theme().primary        // Primary accent
cx.theme().destructive    // Danger/error
cx.theme().success        // Success
cx.theme().warning        // Warning

// Border colors
cx.theme().border         // Default border
cx.theme().ring           // Focus ring

Component Examples

组件示例

Button Usage

按钮使用示例

rust
use gpui_component::button::{Button, ButtonVariants};

Button::new("save")
    .label("Save")
    .icon(IconName::Save)
    .primary()
    .on_click(cx.listener(|this, _, window, cx| {
        this.save(window, cx);
    }))
rust
use gpui_component::button::{Button, ButtonVariants};

Button::new("save")
    .label("Save")
    .icon(IconName::Save)
    .primary()
    .on_click(cx.listener(|this, _, window, cx| {
        this.save(window, cx);
    }))

Input with State

带状态的输入框

rust
use gpui_component::input::{Input, InputState};

// Create state
let input_state = cx.new(|cx| InputState::new(cx));

// In render:
Input::new(&self.input_state)
    .placeholder("Enter text...")
    .cleanable(true)
rust
use gpui_component::input::{Input, InputState};

// Create state
let input_state = cx.new(|cx| InputState::new(cx));

// In render:
Input::new(&self.input_state)
    .placeholder("Enter text...")
    .cleanable(true)

PopupMenu / Command Palette

弹出菜单/命令面板

rust
use gpui_component::menu::{PopupMenu, PopupMenuItem};

let menu = cx.new(|cx| {
    PopupMenu::build(cx, |menu, window, cx| {
        menu.menu_item(PopupMenuItem::new("New File")
            .icon(IconName::FilePlus)
            .action(Box::new(NewFile)))
        .separator()
        .menu_item(PopupMenuItem::new("Save")
            .icon(IconName::Save)
            .action(Box::new(Save)))
    })
});
rust
use gpui_component::menu::{PopupMenu, PopupMenuItem};

let menu = cx.new(|cx| {
    PopupMenu::build(cx, |menu, window, cx| {
        menu.menu_item(PopupMenuItem::new("New File")
            .icon(IconName::FilePlus)
            .action(Box::new(NewFile)))
        .separator()
        .menu_item(PopupMenuItem::new("Save")
            .icon(IconName::Save)
            .action(Box::new(Save)))
    })
});

Completion Provider

补全提供器

rust
use gpui_component::input::{CompletionProvider, InputState};

struct MyCompletionProvider;

impl CompletionProvider for MyCompletionProvider {
    fn completions(
        &self,
        text: &Rope,
        offset: usize,
        trigger: CompletionContext,
        window: &mut Window,
        cx: &mut Context<InputState>,
    ) -> Task<Result<CompletionResponse>> {
        let items = vec![
            CompletionItem {
                label: "option1".into(),
                ..Default::default()
            },
        ];
        Task::ready(Ok(CompletionResponse::Array(items)))
    }
    
    fn is_completion_trigger(
        &self,
        offset: usize,
        new_text: &str,
        cx: &mut Context<InputState>,
    ) -> bool {
        new_text == "/" || new_text == "@"
    }
}
rust
use gpui_component::input::{CompletionProvider, InputState};

struct MyCompletionProvider;

impl CompletionProvider for MyCompletionProvider {
    fn completions(
        &self,
        text: &Rope,
        offset: usize,
        trigger: CompletionContext,
        window: &mut Window,
        cx: &mut Context<InputState>,
    ) -> Task<Result<CompletionResponse>> {
        let items = vec![
            CompletionItem {
                label: "option1".into(),
                ..Default::default()
            },
        ];
        Task::ready(Ok(CompletionResponse::Array(items)))
    }
    
    fn is_completion_trigger(
        &self,
        offset: usize,
        new_text: &str,
        cx: &mut Context<InputState>,
    ) -> bool {
        new_text == "/" || new_text == "@"
    }
}

Reference Files

参考文档

For detailed patterns, read:
  • reference/components.md
    - Full component API
  • reference/theming.md
    - Theme system details
  • reference/input-lsp.md
    - Input with completions
  • reference/menus.md
    - Menu and command palette
如需了解详细模式,请阅读:
  • reference/components.md
    - 完整组件API
  • reference/theming.md
    - 主题系统详情
  • reference/input-lsp.md
    - 带补全的输入框
  • reference/menus.md
    - 菜单与命令面板

Project Setup

项目设置

Cargo.toml

Cargo.toml

toml
[dependencies]
gpui = "0.2"
gpui-component = { version = "0.4", features = ["webview"] }
toml
[dependencies]
gpui = "0.2"
gpui-component = { version = "0.4", features = ["webview"] }

Basic App Structure

基础应用结构

rust
use gpui::*;
use gpui_component::*;

struct App {
    // state
}

impl Render for App {
    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        Root::new(
            div()
                .size_full()
                .flex()
                .flex_col()
                .bg(cx.theme().background)
                .child(self.render_toolbar(window, cx))
                .child(self.render_content(window, cx)),
            window,
            cx
        )
    }
}

fn main() {
    Application::new().run(|cx| {
        gpui_component::init(cx);
        cx.open_window(WindowOptions::default(), |window, cx| {
            cx.new(|cx| App::new(cx))
        });
    });
}
rust
use gpui::*;
use gpui_component::*;

struct App {
    // state
}

impl Render for App {
    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        Root::new(
            div()
                .size_full()
                .flex()
                .flex_col()
                .bg(cx.theme().background)
                .child(self.render_toolbar(window, cx))
                .child(self.render_content(window, cx)),
            window,
            cx
        )
    }
}

fn main() {
    Application::new().run(|cx| {
        gpui_component::init(cx);
        cx.open_window(WindowOptions::default(), |window, cx| {
            cx.new(|cx| App::new(cx))
        });
    });
}