Mainline GPUI2 UI work (#3079)

This PR mainlines the current state of new GPUI2-based UI from the
`gpui2-ui` branch.

Release Notes:

- N/A

---------

Co-authored-by: Nate Butler <iamnbutler@gmail.com>
Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
Co-authored-by: Nate <nate@zed.dev>
This commit is contained in:
Marshall Bowers 2023-10-02 18:20:47 -04:00 committed by GitHub
parent 08361eb84e
commit 9e1f7c4c18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 1047 additions and 399 deletions

View file

@ -12,6 +12,8 @@ path = "src/storybook.rs"
anyhow.workspace = true
clap = { version = "4.4", features = ["derive", "string"] }
chrono = "0.4"
fs = { path = "../fs" }
futures.workspace = true
gpui2 = { path = "../gpui2" }
itertools = "0.11.0"
log.workspace = true

View file

@ -1,5 +1,8 @@
use std::path::PathBuf;
use std::str::FromStr;
use ui::prelude::*;
use ui::Breadcrumb;
use ui::{Breadcrumb, HighlightedText, Symbol};
use crate::story::Story;
@ -8,9 +11,35 @@ pub struct BreadcrumbStory {}
impl BreadcrumbStory {
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx);
Story::container(cx)
.child(Story::title_for::<_, Breadcrumb>(cx))
.child(Story::label(cx, "Default"))
.child(Breadcrumb::new())
.child(Breadcrumb::new(
PathBuf::from_str("crates/ui/src/components/toolbar.rs").unwrap(),
vec![
Symbol(vec![
HighlightedText {
text: "impl ".to_string(),
color: HighlightColor::Keyword.hsla(&theme),
},
HighlightedText {
text: "BreadcrumbStory".to_string(),
color: HighlightColor::Function.hsla(&theme),
},
]),
Symbol(vec![
HighlightedText {
text: "fn ".to_string(),
color: HighlightColor::Keyword.hsla(&theme),
},
HighlightedText {
text: "render".to_string(),
color: HighlightColor::Function.hsla(&theme),
},
]),
],
))
}
}

View file

@ -12,8 +12,10 @@ pub struct BufferStory {}
impl BufferStory {
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx);
Story::container(cx)
.child(Story::title_for::<_, Buffer<V>>(cx))
.child(Story::title_for::<_, Buffer>(cx))
.child(Story::label(cx, "Default"))
.child(div().w(rems(64.)).h_96().child(empty_buffer_example()))
.child(Story::label(cx, "Hello World (Rust)"))
@ -21,14 +23,14 @@ impl BufferStory {
div()
.w(rems(64.))
.h_96()
.child(hello_world_rust_buffer_example(cx)),
.child(hello_world_rust_buffer_example(&theme)),
)
.child(Story::label(cx, "Hello World (Rust) with Status"))
.child(
div()
.w(rems(64.))
.h_96()
.child(hello_world_rust_buffer_with_status_example(cx)),
.child(hello_world_rust_buffer_with_status_example(&theme)),
)
}
}

View file

@ -1,6 +1,6 @@
use chrono::DateTime;
use ui::prelude::*;
use ui::{ChatMessage, ChatPanel};
use ui::{ChatMessage, ChatPanel, Panel};
use crate::story::Story;
@ -12,23 +12,35 @@ impl ChatPanelStory {
Story::container(cx)
.child(Story::title_for::<_, ChatPanel<V>>(cx))
.child(Story::label(cx, "Default"))
.child(ChatPanel::new(ScrollState::default()))
.child(Panel::new(
ScrollState::default(),
|_, _| vec![ChatPanel::new(ScrollState::default()).into_any()],
Box::new(()),
))
.child(Story::label(cx, "With Mesages"))
.child(ChatPanel::new(ScrollState::default()).with_messages(vec![
ChatMessage::new(
"osiewicz".to_string(),
"is this thing on?".to_string(),
DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
.unwrap()
.naive_local(),
),
ChatMessage::new(
"maxdeviant".to_string(),
"Reading you loud and clear!".to_string(),
DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
.unwrap()
.naive_local(),
),
]))
.child(Panel::new(
ScrollState::default(),
|_, _| {
vec![ChatPanel::new(ScrollState::default())
.with_messages(vec![
ChatMessage::new(
"osiewicz".to_string(),
"is this thing on?".to_string(),
DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
.unwrap()
.naive_local(),
),
ChatMessage::new(
"maxdeviant".to_string(),
"Reading you loud and clear!".to_string(),
DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
.unwrap()
.naive_local(),
),
])
.into_any()]
},
Box::new(()),
))
}
}

View file

@ -11,7 +11,7 @@ impl FacepileStory {
let players = static_players();
Story::container(cx)
.child(Story::title_for::<_, ui::Facepile>(cx))
.child(Story::title_for::<_, Facepile>(cx))
.child(Story::label(cx, "Default"))
.child(
div()

View file

@ -14,9 +14,10 @@ impl PanelStory {
.child(Panel::new(
ScrollState::default(),
|_, _| {
(0..100)
.map(|ix| Label::new(format!("Item {}", ix + 1)).into_any())
.collect()
vec![div()
.overflow_y_scroll(ScrollState::default())
.children((0..100).map(|ix| Label::new(format!("Item {}", ix + 1))))
.into_any()]
},
Box::new(()),
))

View file

@ -1,5 +1,5 @@
use ui::prelude::*;
use ui::ProjectPanel;
use ui::{Panel, ProjectPanel};
use crate::story::Story;
@ -11,6 +11,10 @@ impl ProjectPanelStory {
Story::container(cx)
.child(Story::title_for::<_, ProjectPanel<V>>(cx))
.child(Story::label(cx, "Default"))
.child(ProjectPanel::new(ScrollState::default()))
.child(Panel::new(
ScrollState::default(),
|_, _| vec![ProjectPanel::new(ScrollState::default()).into_any()],
Box::new(()),
))
}
}

View file

@ -1,5 +1,5 @@
use ui::prelude::*;
use ui::TabBar;
use ui::{Tab, TabBar};
use crate::story::Story;
@ -11,6 +11,36 @@ impl TabBarStory {
Story::container(cx)
.child(Story::title_for::<_, TabBar<V>>(cx))
.child(Story::label(cx, "Default"))
.child(TabBar::new(ScrollState::default()))
.child(TabBar::new(vec![
Tab::new()
.title("Cargo.toml".to_string())
.current(false)
.git_status(GitStatus::Modified),
Tab::new()
.title("Channels Panel".to_string())
.current(false),
Tab::new()
.title("channels_panel.rs".to_string())
.current(true)
.git_status(GitStatus::Modified),
Tab::new()
.title("workspace.rs".to_string())
.current(false)
.git_status(GitStatus::Modified),
Tab::new()
.title("icon_button.rs".to_string())
.current(false),
Tab::new()
.title("storybook.rs".to_string())
.current(false)
.git_status(GitStatus::Created),
Tab::new().title("theme.rs".to_string()).current(false),
Tab::new()
.title("theme_registry.rs".to_string())
.current(false),
Tab::new()
.title("styleable_helpers.rs".to_string())
.current(false),
]))
}
}

View file

@ -1,5 +1,9 @@
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use ui::prelude::*;
use ui::Toolbar;
use ui::{theme, Breadcrumb, HighlightColor, HighlightedText, Icon, IconButton, Symbol, Toolbar};
use crate::story::Story;
@ -8,9 +12,59 @@ pub struct ToolbarStory {}
impl ToolbarStory {
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx);
struct LeftItemsPayload {
pub theme: Arc<Theme>,
}
Story::container(cx)
.child(Story::title_for::<_, Toolbar>(cx))
.child(Story::title_for::<_, Toolbar<V>>(cx))
.child(Story::label(cx, "Default"))
.child(Toolbar::new())
.child(Toolbar::new(
|_, payload| {
let payload = payload.downcast_ref::<LeftItemsPayload>().unwrap();
let theme = payload.theme.clone();
vec![Breadcrumb::new(
PathBuf::from_str("crates/ui/src/components/toolbar.rs").unwrap(),
vec![
Symbol(vec![
HighlightedText {
text: "impl ".to_string(),
color: HighlightColor::Keyword.hsla(&theme),
},
HighlightedText {
text: "ToolbarStory".to_string(),
color: HighlightColor::Function.hsla(&theme),
},
]),
Symbol(vec![
HighlightedText {
text: "fn ".to_string(),
color: HighlightColor::Keyword.hsla(&theme),
},
HighlightedText {
text: "render".to_string(),
color: HighlightColor::Function.hsla(&theme),
},
]),
],
)
.into_any()]
},
Box::new(LeftItemsPayload {
theme: theme.clone(),
}),
|_, _| {
vec![
IconButton::new(Icon::InlayHint).into_any(),
IconButton::new(Icon::MagnifyingGlass).into_any(),
IconButton::new(Icon::MagicWand).into_any(),
]
},
Box::new(()),
))
}
}

View file

@ -9,7 +9,7 @@ pub struct AvatarStory {}
impl AvatarStory {
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
Story::container(cx)
.child(Story::title_for::<_, ui::Avatar>(cx))
.child(Story::title_for::<_, Avatar>(cx))
.child(Story::label(cx, "Default"))
.child(Avatar::new(
"https://avatars.githubusercontent.com/u/1714999?v=4",

View file

@ -12,7 +12,7 @@ impl IconStory {
let icons = Icon::iter();
Story::container(cx)
.child(Story::title_for::<_, ui::IconElement>(cx))
.child(Story::title_for::<_, IconElement>(cx))
.child(Story::label(cx, "All Icons"))
.child(div().flex().gap_3().children(icons.map(IconElement::new)))
}

View file

@ -19,5 +19,8 @@ impl KitchenSinkStory {
.child(div().flex().flex_col().children_any(element_stories))
.child(Story::label(cx, "Components"))
.child(div().flex().flex_col().children_any(component_stories))
// Add a bit of space at the bottom of the kitchen sink so elements
// don't end up squished right up against the bottom of the screen.
.child(div().p_4())
}
}

View file

@ -4,7 +4,7 @@ mod stories;
mod story;
mod story_selector;
use std::sync::Arc;
use std::{process::Command, sync::Arc};
use ::theme as legacy_theme;
use clap::Parser;
@ -38,11 +38,44 @@ struct Args {
theme: Option<String>,
}
async fn watch_zed_changes(fs: Arc<dyn fs::Fs>) -> Option<()> {
if std::env::var("ZED_HOT_RELOAD").is_err() {
return None;
}
use futures::StreamExt;
let mut events = fs
.watch(".".as_ref(), std::time::Duration::from_millis(100))
.await;
let mut current_child: Option<std::process::Child> = None;
while let Some(events) = events.next().await {
if !events.iter().any(|event| {
event
.path
.to_str()
.map(|path| path.contains("/crates/"))
.unwrap_or_default()
}) {
continue;
}
let child = current_child.take().map(|mut child| child.kill());
log::info!("Storybook changed, rebuilding...");
current_child = Some(
Command::new("cargo")
.args(["run", "-p", "storybook"])
.spawn()
.ok()?,
);
}
Some(())
}
fn main() {
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
let args = Args::parse();
let fs = Arc::new(fs::RealFs);
gpui2::App::new(Assets).unwrap().run(move |cx| {
let mut store = SettingsStore::default();
store
@ -63,6 +96,10 @@ fn main() {
})
.and_then(|theme_name| theme_registry.get(&theme_name).ok());
cx.spawn(|_| async move {
watch_zed_changes(fs).await;
})
.detach();
cx.add_window(
gpui2::WindowOptions {
bounds: WindowBounds::Fixed(RectF::new(vec2f(0., 0.), vec2f(1700., 980.))),