examples: Add examples folder. (#1378)
This commit is contained in:
parent
6998708b81
commit
4ccd7d99d0
12 changed files with 287 additions and 14 deletions
19
Cargo.lock
generated
19
Cargo.lock
generated
|
|
@ -92,6 +92,16 @@ version = "1.0.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "app_assets"
|
||||||
|
version = "0.2.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"gpui",
|
||||||
|
"gpui-component",
|
||||||
|
"rust-embed",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arbitrary"
|
name = "arbitrary"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
|
|
@ -8760,6 +8770,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "window_title"
|
||||||
|
version = "0.2.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"gpui",
|
||||||
|
"gpui-component",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows"
|
name = "windows"
|
||||||
version = "0.57.0"
|
version = "0.57.0"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["crates/hello_world", "crates/macros", "crates/story", "crates/ui"]
|
members = ["examples/hello_world", "examples/window_title", "crates/macros", "crates/story", "crates/ui", "examples/window_title", "examples/app_assets", "examples/app_assets"]
|
||||||
|
|
||||||
default-members = ["crates/story"]
|
default-members = ["crates/story"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
|
||||||
18
examples/README.md
Normal file
18
examples/README.md
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# GPUI Component basic examples
|
||||||
|
|
||||||
|
This folder contains basic examples of how to use the GPUI Component library. Each example demonstrates a specific feature or functionality of the library.
|
||||||
|
|
||||||
|
Unlike the examples in the `story` folder, these examples focus on 1 example for 1 feature, making it easier to understand and implement specific functionalities in your own projects.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Feel free to contribute more examples to this folder!
|
||||||
|
|
||||||
|
If you have a specific use case or feature you'd like to demonstrate, please create a new example file and submit a pull request. We will happy to merge it into the repository.
|
||||||
|
|
||||||
|
When creating a new example, please follow these guidelines:
|
||||||
|
|
||||||
|
1. Keep 1 example just doing 1 thing for more clarity.
|
||||||
|
2. Testing the example to ensure it works as expected.
|
||||||
|
3. Write some comment at some key parts of the code to explain what it does.
|
||||||
|
4. Following the code style and name style used in the existing examples or in entire of GPUI Component.
|
||||||
15
examples/app_assets/Cargo.toml
Normal file
15
examples/app_assets/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
edition = "2021"
|
||||||
|
name = "app_assets"
|
||||||
|
description = "Example to load icons or images from assets folder."
|
||||||
|
publish = false
|
||||||
|
version = "0.2.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow.workspace = true
|
||||||
|
gpui.workspace = true
|
||||||
|
gpui-component = { workspace = true }
|
||||||
|
rust-embed = { version = "8", features = ["interpolate-folder-path"] }
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
62
examples/app_assets/README.md
Normal file
62
examples/app_assets/README.md
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
## Icon assets in GPUI Component
|
||||||
|
|
||||||
|
The [IconName](https://github.com/longbridge/gpui-component/blob/6998708b817024c2ac0f1ea164d74ddfc024e124/crates/ui/src/icon.rs#L9) is a enum that defined a bunch of icon names, because some internal components in GPUI Component will use them.
|
||||||
|
|
||||||
|
You can see, we have a lot of svg icon files in the `assets/icons` folder, but we are not embed all of the icon files in the library by default. This for keep the library size small.
|
||||||
|
|
||||||
|
So you must have your own icon files to use the `Icon` component in GPUI Component.
|
||||||
|
|
||||||
|
You can download the icon files from [here](https://lucide.dev/) or use your own icon files as you wish, just use the same filename as the icon name (match with the `IconName` defined) you want to use.
|
||||||
|
|
||||||
|
For example your assets folder:
|
||||||
|
|
||||||
|
```
|
||||||
|
app_root
|
||||||
|
assets
|
||||||
|
icons
|
||||||
|
close.svg
|
||||||
|
menu.svg
|
||||||
|
...
|
||||||
|
src
|
||||||
|
main.rs
|
||||||
|
Cargo.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
You also can just copy the svg files you want from the `assets/icons` folder in GPUI Component repo to your own assets folder.
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
You need define a `Assets` struct with rust-embed to register assets to GPUI application.
|
||||||
|
|
||||||
|
```rs
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use gpui::*;
|
||||||
|
use rust_embed::RustEmbed;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
#[derive(RustEmbed)]
|
||||||
|
#[folder = "./assets"]
|
||||||
|
#[include = "icons/**/*.svg"]
|
||||||
|
pub struct Assets;
|
||||||
|
|
||||||
|
impl AssetSource for Assets {
|
||||||
|
fn load(&self, path: &str) -> Result<Option<Cow<'static, [u8]>>> {
|
||||||
|
Self::get(path)
|
||||||
|
.map(|f| Some(f.data))
|
||||||
|
.ok_or_else(|| anyhow!("could not find asset at path \"{path}\""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list(&self, path: &str) -> Result<Vec<SharedString>> {
|
||||||
|
Ok(Self::iter()
|
||||||
|
.filter_map(|p| p.starts_with(path).then(|| p.into()))
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Call with_assets to register assets
|
||||||
|
let app = Application::new().with_assets(Assets);
|
||||||
|
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
14
examples/app_assets/assets/icons/bot.svg
Normal file
14
examples/app_assets/assets/icons/bot.svg
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="lucide lucide-bot"
|
||||||
|
><path d="M12 8V4H8" /><rect width="16" height="12" x="4" y="8" rx="2" /><path
|
||||||
|
d="M2 14h2"
|
||||||
|
/><path d="M20 14h2" /><path d="M15 13v2" /><path d="M9 13v2" /></svg>
|
||||||
|
After Width: | Height: | Size: 421 B |
14
examples/app_assets/assets/icons/inbox.svg
Normal file
14
examples/app_assets/assets/icons/inbox.svg
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="lucide lucide-inbox"
|
||||||
|
><polyline points="22 12 16 12 14 15 10 15 8 12 2 12" /><path
|
||||||
|
d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"
|
||||||
|
/></svg>
|
||||||
|
After Width: | Height: | Size: 443 B |
64
examples/app_assets/src/main.rs
Normal file
64
examples/app_assets/src/main.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use gpui::*;
|
||||||
|
use gpui_component::{v_flex, IconName, Root};
|
||||||
|
use rust_embed::RustEmbed;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
/// An asset source that loads assets from the `./assets` folder.
|
||||||
|
#[derive(RustEmbed)]
|
||||||
|
#[folder = "./assets"]
|
||||||
|
#[include = "icons/**/*.svg"]
|
||||||
|
pub struct Assets;
|
||||||
|
|
||||||
|
impl AssetSource for Assets {
|
||||||
|
fn load(&self, path: &str) -> Result<Option<Cow<'static, [u8]>>> {
|
||||||
|
if path.is_empty() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::get(path)
|
||||||
|
.map(|f| Some(f.data))
|
||||||
|
.ok_or_else(|| anyhow!("could not find asset at path \"{path}\""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list(&self, path: &str) -> Result<Vec<SharedString>> {
|
||||||
|
Ok(Self::iter()
|
||||||
|
.filter_map(|p| p.starts_with(path).then(|| p.into()))
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Example;
|
||||||
|
impl Render for Example {
|
||||||
|
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
v_flex()
|
||||||
|
.gap_2()
|
||||||
|
.size_full()
|
||||||
|
.items_center()
|
||||||
|
.justify_center()
|
||||||
|
.text_center()
|
||||||
|
.child(IconName::Inbox)
|
||||||
|
.child(IconName::Bot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Register Assets to GPUI application.
|
||||||
|
let app = Application::new().with_assets(Assets);
|
||||||
|
|
||||||
|
app.run(move |cx| {
|
||||||
|
// We must initialize gpui_component before using it.
|
||||||
|
gpui_component::init(cx);
|
||||||
|
|
||||||
|
cx.spawn(async move |cx| {
|
||||||
|
cx.open_window(WindowOptions::default(), |window, cx| {
|
||||||
|
let view = cx.new(|_| Example);
|
||||||
|
// The first level on the window must be Root.
|
||||||
|
cx.new(|cx| Root::new(view.into(), window, cx))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok::<_, anyhow::Error>(())
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -29,6 +29,7 @@ fn main() {
|
||||||
let app = Application::new();
|
let app = Application::new();
|
||||||
|
|
||||||
app.run(move |cx| {
|
app.run(move |cx| {
|
||||||
|
// We must initialize gpui_component before using it.
|
||||||
gpui_component::init(cx);
|
gpui_component::init(cx);
|
||||||
|
|
||||||
cx.activate(true);
|
cx.activate(true);
|
||||||
|
|
@ -57,19 +58,11 @@ fn main() {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let window = cx
|
cx.open_window(options, |window, cx| {
|
||||||
.open_window(options, |window, cx| {
|
|
||||||
let view = cx.new(|_| HelloWorld);
|
let view = cx.new(|_| HelloWorld);
|
||||||
|
// The first level on the window must be Root.
|
||||||
cx.new(|cx| Root::new(view.into(), window, cx))
|
cx.new(|cx| Root::new(view.into(), window, cx))
|
||||||
})
|
})?;
|
||||||
.expect("failed to open window");
|
|
||||||
|
|
||||||
window
|
|
||||||
.update(cx, |_, window, _| {
|
|
||||||
window.activate_window();
|
|
||||||
window.set_window_title("Example");
|
|
||||||
})
|
|
||||||
.expect("failed to update window");
|
|
||||||
|
|
||||||
Ok::<_, anyhow::Error>(())
|
Ok::<_, anyhow::Error>(())
|
||||||
})
|
})
|
||||||
14
examples/window_title/Cargo.toml
Normal file
14
examples/window_title/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
[package]
|
||||||
|
edition = "2021"
|
||||||
|
name = "window_title"
|
||||||
|
description = "An example of using gpui-component to create a window with a custom title bar."
|
||||||
|
publish = false
|
||||||
|
version = "0.2.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow.workspace = true
|
||||||
|
gpui.workspace = true
|
||||||
|
gpui-component = { workspace = true }
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
60
examples/window_title/src/main.rs
Normal file
60
examples/window_title/src/main.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
use gpui::*;
|
||||||
|
use gpui_component::{
|
||||||
|
button::{Button, ButtonVariants},
|
||||||
|
v_flex, Root, TitleBar,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Example;
|
||||||
|
impl Render for Example {
|
||||||
|
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
v_flex()
|
||||||
|
.size_full()
|
||||||
|
.child(
|
||||||
|
// Render custom title bar on top of Root view.
|
||||||
|
TitleBar::new()
|
||||||
|
.justify_between()
|
||||||
|
.pr_2()
|
||||||
|
.child("App with Custom title bar")
|
||||||
|
.child("Right Item"),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.id("window-body")
|
||||||
|
.p_5()
|
||||||
|
.size_full()
|
||||||
|
.items_center()
|
||||||
|
.justify_center()
|
||||||
|
.child("Hello, World!")
|
||||||
|
.child(
|
||||||
|
Button::new("ok")
|
||||||
|
.primary()
|
||||||
|
.label("Let's Go!")
|
||||||
|
.on_click(|_, _, _| println!("Clicked!")),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let app = Application::new();
|
||||||
|
|
||||||
|
app.run(move |cx| {
|
||||||
|
gpui_component::init(cx);
|
||||||
|
|
||||||
|
cx.spawn(async move |cx| {
|
||||||
|
let window_options = WindowOptions {
|
||||||
|
// Setup GPUI to use custom title bar
|
||||||
|
titlebar: Some(TitleBar::title_bar_options()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
cx.open_window(window_options, |window, cx| {
|
||||||
|
let view = cx.new(|_| Example);
|
||||||
|
cx.new(|cx| Root::new(view.into(), window, cx))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok::<_, anyhow::Error>(())
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue