T48d Docs · Getting started: four steps, a window that follows the theme, changing state from a press; the start example compiles
This commit is contained in:
1 parent
e36a0c49af
commit
3ca27c00d9
4 files changed
+99
-1
No files matched your search
@@ -91,3 +91,7 @@ path = "examples/gallery/main.rs"
|
|||||||
[[example]]
|
[[example]]
|
||||||
name = "docs_hello"
|
name = "docs_hello"
|
||||||
path = "examples/docs/hello.rs"
|
path = "examples/docs/hello.rs"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "docs_start"
|
||||||
|
path = "examples/docs/start.rs"
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
use ely_gpui_component::{
|
||||||
|
Assets,
|
||||||
|
buttons::Button,
|
||||||
|
primitives::FocusScope,
|
||||||
|
theme::{ActiveTheme, Mode, Theme},
|
||||||
|
typography::{Heading, Paragraph},
|
||||||
|
};
|
||||||
|
use gpui::{
|
||||||
|
App, AppContext, Bounds, Context, FocusHandle, IntoElement, ParentElement, Render, Styled,
|
||||||
|
TitlebarOptions, Window, WindowBounds, WindowOptions, px, size,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Start {
|
||||||
|
focus: FocusHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for Start {
|
||||||
|
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
let theme = cx.theme();
|
||||||
|
let next = if theme.is_dark() {
|
||||||
|
Mode::Light
|
||||||
|
} else {
|
||||||
|
Mode::Dark
|
||||||
|
};
|
||||||
|
FocusScope::new(&self.focus)
|
||||||
|
.root()
|
||||||
|
.size_full()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.gap_4()
|
||||||
|
.p_8()
|
||||||
|
.bg(theme.colors.bg)
|
||||||
|
.child(Heading::h1("Start"))
|
||||||
|
.child(Paragraph::new(
|
||||||
|
"Every Ely component reads the theme, so one call turns them all.",
|
||||||
|
))
|
||||||
|
.child(
|
||||||
|
Button::new("mode", format!("{next:?} mode"))
|
||||||
|
.on_click(move |_, _, cx| Theme::set_mode(next, cx)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
gpui_platform::application()
|
||||||
|
.with_assets(Assets)
|
||||||
|
.run(|cx: &mut App| {
|
||||||
|
ely_gpui_component::init(cx);
|
||||||
|
Theme::set_mode_now(Mode::Dark, cx);
|
||||||
|
let bounds = Bounds::centered(None, size(px(640.0), px(400.0)), cx);
|
||||||
|
let options = WindowOptions {
|
||||||
|
window_bounds: Some(WindowBounds::Windowed(bounds)),
|
||||||
|
titlebar: Some(TitlebarOptions {
|
||||||
|
title: Some("Start".into()),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
cx.open_window(options, |window, cx| {
|
||||||
|
cx.new(|cx| {
|
||||||
|
let focus = cx.focus_handle();
|
||||||
|
window.focus(&focus, cx);
|
||||||
|
Start { focus }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.expect("window failed to open");
|
||||||
|
cx.activate(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Getting started
|
||||||
|
|
||||||
|
An Ely app is a GPUI app with three more parts: Ely's assets, one call to `init`, and a root `FocusScope` around each window's content.
|
||||||
|
|
||||||
|
## Four steps
|
||||||
|
|
||||||
|
| Step | Why |
|
||||||
|
| --- | --- |
|
||||||
|
| `gpui_platform::application().with_assets(Assets)` | Ely embeds its icons and fonts. `init` panics without them. |
|
||||||
|
| `ely_gpui_component::init(cx)` | Call once, before any window. It registers the fonts, sets the theme, and binds Tab, Shift-Tab and the keys of text fields, the code editor, documents and, natively, the terminal. |
|
||||||
|
| A root `FocusScope` | `FocusScope::new(&handle).root()` owns Tab for the window and takes focus back when the focused element leaves the tree. Focus its handle when the window opens. |
|
||||||
|
| `cx.theme()` | Colors, sizes and radii come from the theme. Components read it; an app's own boxes read it too. |
|
||||||
|
|
||||||
|
## A window that follows the theme
|
||||||
|
|
||||||
|
The example opens a titled window in dark mode. Its button cross-fades every component to the other mode.
|
||||||
|
|
||||||
|
```rust example=start
|
||||||
|
```
|
||||||
|
|
||||||
|
`Theme::set_mode_now` before the window opens makes the first frame dark. `Theme::set_mode` fades the palette and repaints every window as it goes, so the button needs no `notify`. `Heading` and `Paragraph` take their size, weight and color from the theme.
|
||||||
|
|
||||||
|
## Changing state from a press
|
||||||
|
|
||||||
|
`Button::on_click` takes a closure over `&ClickEvent`, `&mut Window` and `&mut App`. To change a view's own state, capture the view with `cx.entity()` in `render`, update it in the closure, and call `cx.notify()`. The [first window](/docs/#a-first-window) counts presses that way. A change made outside `render` without `cx.notify()` draws nothing.
|
||||||
@@ -6,7 +6,7 @@ import { Marked, type Tokens } from "marked";
|
|||||||
const at = (relative: string) => fileURLToPath(new URL(relative, import.meta.url));
|
const at = (relative: string) => fileURLToPath(new URL(relative, import.meta.url));
|
||||||
|
|
||||||
/** The guides in reading order, by file name. */
|
/** The guides in reading order, by file name. */
|
||||||
const ORDER = ["introduction", "installation"];
|
const ORDER = ["introduction", "installation", "getting-started"];
|
||||||
|
|
||||||
export interface Guide {
|
export interface Guide {
|
||||||
/** The path segment; the introduction has none. */
|
/** The path segment; the introduction has none. */
|
||||||
|
|||||||
Reference in new issue
Block a user