Demos that open a second window, take files, move the window, read the clipboard or set native menus show a note on the web in the blocked style. IBM Plex Sans Regular joins the assets, unmodified, where gpui's svg renderer loads it: gpui_web answers .SystemUIFont with it. The gallery's web entry registers a Hebrew cut of Noto Sans Hebrew. scripts/web.sh builds the bundle with wasm-bindgen and wasm-opt -Oz, 20.0 MB, and fails past 25 MiB.
176 lines
5.3 KiB
Rust
176 lines
5.3 KiB
Rust
use ely_gpui_component::{
|
|
forms::{
|
|
ExpressionInput, HotkeyInput, KeyValueInput, ListInput, MentionInput, PathInput,
|
|
RegexInput, TagInput, expression_highlights, mention_highlights, regex_highlights,
|
|
},
|
|
typography::Caption,
|
|
};
|
|
use gpui::{App, IntoElement, Keystroke, ParentElement, SharedString, Styled, Window, div, px};
|
|
|
|
use super::text::field;
|
|
use crate::{
|
|
probe::probe,
|
|
ui::{NO_FILES, code, section, web_note},
|
|
};
|
|
|
|
pub fn mention(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
|
let message = field("input-mention", window, cx, |input| {
|
|
input
|
|
.multi_line(2, 5)
|
|
.placeholder("Write a note. @ for people, # for tags.")
|
|
.highlighter(mention_highlights)
|
|
});
|
|
section(
|
|
"MentionInput / HashtagInput",
|
|
"@ and # open suggestions at the caret. Arrows choose, Enter picks.",
|
|
cx,
|
|
)
|
|
.child(probe(
|
|
"mention",
|
|
div().w(px(420.0)).child(
|
|
MentionInput::new("mentions", &message)
|
|
.trigger('@', ["ada", "alan", "grace", "linus"])
|
|
.trigger('#', ["release", "research", "design", "docs"]),
|
|
),
|
|
))
|
|
}
|
|
|
|
pub fn tags(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
|
let tags = window.use_keyed_state("tags", cx, |_, _| {
|
|
vec![SharedString::from("rust"), SharedString::from("gpui")]
|
|
});
|
|
let now = tags.read(cx).clone();
|
|
section(
|
|
"TagInput / TokenInput",
|
|
"Enter or a comma adds a chip; Backspace on an empty field drops the last.",
|
|
cx,
|
|
)
|
|
.child(probe(
|
|
"tags",
|
|
div().w(px(420.0)).child(
|
|
TagInput::new("topic-tags", now).on_change(move |next, _, cx| {
|
|
tags.update(cx, |tags, cx| {
|
|
*tags = next;
|
|
cx.notify();
|
|
})
|
|
}),
|
|
),
|
|
))
|
|
}
|
|
|
|
pub fn rows(cx: &App) -> impl IntoElement + use<> {
|
|
section(
|
|
"KeyValueInput / ListInput",
|
|
"Rows you add and remove. Each row reports as you type.",
|
|
cx,
|
|
)
|
|
.child(
|
|
div()
|
|
.flex()
|
|
.gap_8()
|
|
.child(
|
|
div().w(px(380.0)).child(
|
|
KeyValueInput::new(
|
|
"env",
|
|
[
|
|
("RUST_LOG".to_string(), "info".to_string()),
|
|
("PORT".to_string(), "8080".to_string()),
|
|
],
|
|
)
|
|
.on_change(|pairs, _, _| log::info!("gallery: {} pairs", pairs.len())),
|
|
),
|
|
)
|
|
.child(
|
|
div().w(px(240.0)).child(
|
|
ListInput::new("hosts", ["ely.dev".to_string()])
|
|
.placeholder("Host")
|
|
.on_change(|items, _, _| log::info!("gallery: {} hosts", items.len())),
|
|
),
|
|
),
|
|
)
|
|
}
|
|
|
|
pub fn path(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
|
let folder = field("input-path", window, cx, |input| {
|
|
input.placeholder("~/Projects")
|
|
});
|
|
section(
|
|
"PathInput",
|
|
"Type a path, or Browse with the system's dialog.",
|
|
cx,
|
|
)
|
|
.children(web_note(NO_FILES, cx))
|
|
.child(probe(
|
|
"path",
|
|
div()
|
|
.w(px(420.0))
|
|
.child(PathInput::new("path-browse", &folder).directories()),
|
|
))
|
|
}
|
|
|
|
pub fn regex(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
|
let pattern = field("input-regex", window, cx, |input| {
|
|
input.placeholder("^[a-z]+$").highlighter(regex_highlights)
|
|
});
|
|
section(
|
|
"RegexInput",
|
|
"Colored by part as you type; a broken pattern says why.",
|
|
cx,
|
|
)
|
|
.child(probe(
|
|
"regex",
|
|
div().w(px(420.0)).child(RegexInput::new(&pattern)),
|
|
))
|
|
}
|
|
|
|
pub fn expression(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
|
let formula = field("input-formula", window, cx, |input| {
|
|
input
|
|
.placeholder("price * qty")
|
|
.highlighter(expression_highlights)
|
|
});
|
|
section(
|
|
"ExpressionInput",
|
|
"A formula, colored and evaluated as you type.",
|
|
cx,
|
|
)
|
|
.child(probe(
|
|
"expression",
|
|
div().w(px(420.0)).child(
|
|
ExpressionInput::new(&formula)
|
|
.variable("price", 12.5)
|
|
.variable("qty", 3.0),
|
|
),
|
|
))
|
|
.child(code(
|
|
"price = 12.5, qty = 3; abs sqrt round floor ceil min max",
|
|
cx,
|
|
))
|
|
}
|
|
|
|
pub fn hotkey(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
|
let recorded = window.use_keyed_state("hotkey", cx, |_, _| Keystroke::parse("cmd-k").ok());
|
|
let now = recorded.read(cx).clone();
|
|
section(
|
|
"HotkeyInput / ShortcutRecorder",
|
|
"Focus it and press a shortcut; it keeps that one and lets go.",
|
|
cx,
|
|
)
|
|
.child(probe(
|
|
"hotkey",
|
|
div()
|
|
.w(px(260.0))
|
|
.child(
|
|
HotkeyInput::new("palette-key", now).on_change(move |next, _, cx| {
|
|
recorded.update(cx, |recorded, cx| {
|
|
*recorded = next;
|
|
cx.notify();
|
|
})
|
|
}),
|
|
),
|
|
))
|
|
.child(Caption::new(
|
|
"Records any key with its modifiers; Tab still moves focus.",
|
|
))
|
|
}
|