gpui: Add a standard text example (#30747)
This is a dumb first pass at a standard text example. We'll use this to start digging in to some text/scale rendering issues. There will be a ton of follow-up features to this, but starting simple. Release Notes: - N/A
This commit is contained in:
parent
9dabf491f0
commit
e26620d1cf
30 changed files with 606 additions and 362 deletions
|
@ -7,11 +7,11 @@ use crate::notifications::collab_notification::CollabNotification;
|
|||
pub struct CollabNotificationStory;
|
||||
|
||||
impl Render for CollabNotificationStory {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let window_container = |width, height| div().w(px(width)).h(px(height));
|
||||
|
||||
Story::container()
|
||||
.child(Story::title_for::<CollabNotification>())
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<CollabNotification>(cx))
|
||||
.child(
|
||||
StorySection::new().child(StoryItem::new(
|
||||
"Incoming Call Notification",
|
||||
|
|
|
@ -257,6 +257,10 @@ path = "examples/image/image.rs"
|
|||
name = "input"
|
||||
path = "examples/input.rs"
|
||||
|
||||
[[example]]
|
||||
name = "on_window_close_quit"
|
||||
path = "examples/on_window_close_quit.rs"
|
||||
|
||||
[[example]]
|
||||
name = "opacity"
|
||||
path = "examples/opacity.rs"
|
||||
|
@ -277,6 +281,10 @@ path = "examples/shadow.rs"
|
|||
name = "svg"
|
||||
path = "examples/svg/svg.rs"
|
||||
|
||||
[[example]]
|
||||
name = "text"
|
||||
path = "examples/text.rs"
|
||||
|
||||
[[example]]
|
||||
name = "text_wrapper"
|
||||
path = "examples/text_wrapper.rs"
|
||||
|
@ -288,7 +296,3 @@ path = "examples/uniform_list.rs"
|
|||
[[example]]
|
||||
name = "window_shadow"
|
||||
path = "examples/window_shadow.rs"
|
||||
|
||||
[[example]]
|
||||
name = "on_window_close_quit"
|
||||
path = "examples/on_window_close_quit.rs"
|
||||
|
|
333
crates/gpui/examples/text.rs
Normal file
333
crates/gpui/examples/text.rs
Normal file
|
@ -0,0 +1,333 @@
|
|||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use gpui::{
|
||||
AbsoluteLength, App, Application, Context, DefiniteLength, ElementId, Global, Hsla, Menu,
|
||||
SharedString, TextStyle, TitlebarOptions, Window, WindowBounds, WindowOptions, bounds,
|
||||
colors::DefaultColors, div, point, prelude::*, px, relative, rgb, size,
|
||||
};
|
||||
use std::iter;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TextContext {
|
||||
font_size: f32,
|
||||
line_height: f32,
|
||||
type_scale: f32,
|
||||
}
|
||||
|
||||
impl Default for TextContext {
|
||||
fn default() -> Self {
|
||||
TextContext {
|
||||
font_size: 16.0,
|
||||
line_height: 1.3,
|
||||
type_scale: 1.33,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TextContext {
|
||||
pub fn get_global(cx: &App) -> &Arc<TextContext> {
|
||||
&cx.global::<GlobalTextContext>().0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GlobalTextContext(pub Arc<TextContext>);
|
||||
|
||||
impl Deref for GlobalTextContext {
|
||||
type Target = Arc<TextContext>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for GlobalTextContext {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Global for GlobalTextContext {}
|
||||
|
||||
pub trait ActiveTextContext {
|
||||
fn text_context(&self) -> &Arc<TextContext>;
|
||||
}
|
||||
|
||||
impl ActiveTextContext for App {
|
||||
fn text_context(&self) -> &Arc<TextContext> {
|
||||
&self.global::<GlobalTextContext>().0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct SpecimenTheme {
|
||||
pub bg: Hsla,
|
||||
pub fg: Hsla,
|
||||
}
|
||||
|
||||
impl Default for SpecimenTheme {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bg: gpui::white(),
|
||||
fg: gpui::black(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpecimenTheme {
|
||||
pub fn invert(&self) -> Self {
|
||||
Self {
|
||||
bg: self.fg,
|
||||
fg: self.bg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, IntoElement)]
|
||||
struct Specimen {
|
||||
id: ElementId,
|
||||
scale: f32,
|
||||
text_style: Option<TextStyle>,
|
||||
string: SharedString,
|
||||
invert: bool,
|
||||
}
|
||||
|
||||
impl Specimen {
|
||||
pub fn new(id: usize) -> Self {
|
||||
let string = SharedString::new_static("The quick brown fox jumps over the lazy dog");
|
||||
let id_string = format!("specimen-{}", id);
|
||||
let id = ElementId::Name(id_string.into());
|
||||
Self {
|
||||
id,
|
||||
scale: 1.0,
|
||||
text_style: None,
|
||||
string,
|
||||
invert: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn invert(mut self) -> Self {
|
||||
self.invert = !self.invert;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn scale(mut self, scale: f32) -> Self {
|
||||
self.scale = scale;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for Specimen {
|
||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let rem_size = window.rem_size();
|
||||
let scale = self.scale;
|
||||
let global_style = cx.text_context();
|
||||
|
||||
let style_override = self.text_style;
|
||||
|
||||
let mut font_size = global_style.font_size;
|
||||
let mut line_height = global_style.line_height;
|
||||
|
||||
if let Some(style_override) = style_override {
|
||||
font_size = style_override.font_size.to_pixels(rem_size).0;
|
||||
line_height = match style_override.line_height {
|
||||
DefiniteLength::Absolute(absolute_len) => match absolute_len {
|
||||
AbsoluteLength::Rems(absolute_len) => absolute_len.to_pixels(rem_size).0,
|
||||
AbsoluteLength::Pixels(absolute_len) => absolute_len.0,
|
||||
},
|
||||
DefiniteLength::Fraction(value) => value,
|
||||
};
|
||||
}
|
||||
|
||||
let mut theme = SpecimenTheme::default();
|
||||
|
||||
if self.invert {
|
||||
theme = theme.invert();
|
||||
}
|
||||
|
||||
div()
|
||||
.id(self.id)
|
||||
.bg(theme.bg)
|
||||
.text_color(theme.fg)
|
||||
.text_size(px(font_size * scale))
|
||||
.line_height(relative(line_height))
|
||||
.p(px(10.0))
|
||||
.child(self.string.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, IntoElement)]
|
||||
struct CharacterGrid {
|
||||
scale: f32,
|
||||
invert: bool,
|
||||
text_style: Option<TextStyle>,
|
||||
}
|
||||
|
||||
impl CharacterGrid {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
scale: 1.0,
|
||||
invert: false,
|
||||
text_style: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scale(mut self, scale: f32) -> Self {
|
||||
self.scale = scale;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for CharacterGrid {
|
||||
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
|
||||
let mut theme = SpecimenTheme::default();
|
||||
|
||||
if self.invert {
|
||||
theme = theme.invert();
|
||||
}
|
||||
|
||||
let characters = vec![
|
||||
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "A", "B", "C", "D", "E", "F", "G",
|
||||
"H", "I", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y",
|
||||
"Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "p", "q",
|
||||
"r", "s", "t", "u", "v", "w", "x", "y", "z", "ẞ", "ſ", "ß", "ð", "Þ", "þ", "α", "β",
|
||||
"Γ", "γ", "Δ", "δ", "η", "θ", "ι", "κ", "Λ", "λ", "μ", "ν", "ξ", "π", "τ", "υ", "φ",
|
||||
"χ", "ψ", "∂", "а", "в", "Ж", "ж", "З", "з", "К", "к", "л", "м", "Н", "н", "Р", "р",
|
||||
"У", "у", "ф", "ч", "ь", "ы", "Э", "э", "Я", "я", "ij", "öẋ", ".,", "⣝⣑", "~", "*",
|
||||
"_", "^", "`", "'", "(", "{", "«", "#", "&", "@", "$", "¢", "%", "|", "?", "¶", "µ",
|
||||
"❮", "<=", "!=", "==", "--", "++", "=>", "->",
|
||||
];
|
||||
|
||||
let columns = 11;
|
||||
let rows = characters.len().div_ceil(columns);
|
||||
|
||||
let grid_rows = (0..rows).map(|row_idx| {
|
||||
let start_idx = row_idx * columns;
|
||||
let end_idx = (start_idx + columns).min(characters.len());
|
||||
|
||||
div()
|
||||
.w_full()
|
||||
.flex()
|
||||
.flex_row()
|
||||
.children((start_idx..end_idx).map(|i| {
|
||||
div()
|
||||
.text_center()
|
||||
.size(px(62.))
|
||||
.bg(theme.bg)
|
||||
.text_color(theme.fg)
|
||||
.text_size(px(24.0))
|
||||
.line_height(relative(1.0))
|
||||
.child(characters[i])
|
||||
}))
|
||||
.when(end_idx - start_idx < columns, |d| {
|
||||
d.children(
|
||||
iter::repeat_with(|| div().flex_1()).take(columns - (end_idx - start_idx)),
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
div().p_4().gap_2().flex().flex_col().children(grid_rows)
|
||||
}
|
||||
}
|
||||
|
||||
struct TextExample {
|
||||
next_id: usize,
|
||||
}
|
||||
|
||||
impl TextExample {
|
||||
fn next_id(&mut self) -> usize {
|
||||
self.next_id += 1;
|
||||
self.next_id
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for TextExample {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let tcx = cx.text_context();
|
||||
let colors = cx.default_colors().clone();
|
||||
|
||||
let type_scale = tcx.type_scale;
|
||||
|
||||
let step_down_2 = 1.0 / (type_scale * type_scale);
|
||||
let step_down_1 = 1.0 / type_scale;
|
||||
let base = 1.0;
|
||||
let step_up_1 = base * type_scale;
|
||||
let step_up_2 = step_up_1 * type_scale;
|
||||
let step_up_3 = step_up_2 * type_scale;
|
||||
let step_up_4 = step_up_3 * type_scale;
|
||||
let step_up_5 = step_up_4 * type_scale;
|
||||
let step_up_6 = step_up_5 * type_scale;
|
||||
|
||||
div()
|
||||
.size_full()
|
||||
.child(
|
||||
div()
|
||||
.id("text-example")
|
||||
.overflow_y_scroll()
|
||||
.overflow_x_hidden()
|
||||
.bg(rgb(0xffffff))
|
||||
.size_full()
|
||||
.child(div().child(CharacterGrid::new().scale(base)))
|
||||
.child(
|
||||
div()
|
||||
.child(Specimen::new(self.next_id()).scale(step_down_2))
|
||||
.child(Specimen::new(self.next_id()).scale(step_down_2).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_down_1))
|
||||
.child(Specimen::new(self.next_id()).scale(step_down_1).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(base))
|
||||
.child(Specimen::new(self.next_id()).scale(base).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_1))
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_1).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_2))
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_2).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_3))
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_3).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_4))
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_4).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_5))
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_5).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_6))
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_6).invert()),
|
||||
),
|
||||
)
|
||||
.child(div().w(px(240.)).h_full().bg(colors.container))
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Application::new().run(|cx: &mut App| {
|
||||
cx.set_menus(vec![Menu {
|
||||
name: "GPUI Typography".into(),
|
||||
items: vec![],
|
||||
}]);
|
||||
|
||||
cx.init_colors();
|
||||
cx.set_global(GlobalTextContext(Arc::new(TextContext::default())));
|
||||
|
||||
let window = cx
|
||||
.open_window(
|
||||
WindowOptions {
|
||||
titlebar: Some(TitlebarOptions {
|
||||
title: Some("GPUI Typography".into()),
|
||||
..Default::default()
|
||||
}),
|
||||
window_bounds: Some(WindowBounds::Windowed(bounds(
|
||||
point(px(0.0), px(0.0)),
|
||||
size(px(920.), px(720.)),
|
||||
))),
|
||||
..Default::default()
|
||||
},
|
||||
|_window, cx| cx.new(|_cx| TextExample { next_id: 0 }),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
window
|
||||
.update(cx, |_view, _window, cx| {
|
||||
cx.activate(true);
|
||||
})
|
||||
.unwrap();
|
||||
});
|
||||
}
|
|
@ -38,7 +38,9 @@ use crate::{
|
|||
PlatformDisplay, PlatformKeyboardLayout, Point, PromptBuilder, PromptHandle, PromptLevel,
|
||||
Render, RenderImage, RenderablePromptHandle, Reservation, ScreenCaptureSource, SharedString,
|
||||
SubscriberSet, Subscription, SvgRenderer, Task, TextSystem, Window, WindowAppearance,
|
||||
WindowHandle, WindowId, WindowInvalidator, current_platform, hash, init_app_menus,
|
||||
WindowHandle, WindowId, WindowInvalidator,
|
||||
colors::{Colors, GlobalColors},
|
||||
current_platform, hash, init_app_menus,
|
||||
};
|
||||
|
||||
mod async_context;
|
||||
|
@ -1656,6 +1658,13 @@ impl App {
|
|||
_ = window.drop_image(image);
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes gpui's default colors for the application.
|
||||
///
|
||||
/// These colors can be accessed through `cx.default_colors()`.
|
||||
pub fn init_colors(&mut self) {
|
||||
self.set_global(GlobalColors(Arc::new(Colors::default())));
|
||||
}
|
||||
}
|
||||
|
||||
impl AppContext for App {
|
||||
|
|
122
crates/gpui/src/colors.rs
Normal file
122
crates/gpui/src/colors.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
use crate::{App, Global, Rgba, Window, WindowAppearance, rgb};
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// The default set of colors for gpui.
|
||||
///
|
||||
/// These are used for styling base components, examples and more.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Colors {
|
||||
/// Text color
|
||||
pub text: Rgba,
|
||||
/// Selected text color
|
||||
pub selected_text: Rgba,
|
||||
/// Background color
|
||||
pub background: Rgba,
|
||||
/// Disabled color
|
||||
pub disabled: Rgba,
|
||||
/// Selected color
|
||||
pub selected: Rgba,
|
||||
/// Border color
|
||||
pub border: Rgba,
|
||||
/// Separator color
|
||||
pub separator: Rgba,
|
||||
/// Container color
|
||||
pub container: Rgba,
|
||||
}
|
||||
|
||||
impl Default for Colors {
|
||||
fn default() -> Self {
|
||||
Self::light()
|
||||
}
|
||||
}
|
||||
|
||||
impl Colors {
|
||||
/// Returns the default colors for the given window appearance.
|
||||
pub fn for_appearance(window: &Window) -> Self {
|
||||
match window.appearance() {
|
||||
WindowAppearance::Light | WindowAppearance::VibrantLight => Self::light(),
|
||||
WindowAppearance::Dark | WindowAppearance::VibrantDark => Self::dark(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the default dark colors.
|
||||
pub fn dark() -> Self {
|
||||
Self {
|
||||
text: rgb(0xffffff),
|
||||
selected_text: rgb(0xffffff),
|
||||
disabled: rgb(0x565656),
|
||||
selected: rgb(0x2457ca),
|
||||
background: rgb(0x222222),
|
||||
border: rgb(0x000000),
|
||||
separator: rgb(0xd9d9d9),
|
||||
container: rgb(0x262626),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the default light colors.
|
||||
pub fn light() -> Self {
|
||||
Self {
|
||||
text: rgb(0x252525),
|
||||
selected_text: rgb(0xffffff),
|
||||
background: rgb(0xffffff),
|
||||
disabled: rgb(0xb0b0b0),
|
||||
selected: rgb(0x2a63d9),
|
||||
border: rgb(0xd9d9d9),
|
||||
separator: rgb(0xe6e6e6),
|
||||
container: rgb(0xf4f5f5),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get [Colors] from the global state
|
||||
pub fn get_global(cx: &App) -> &Arc<Colors> {
|
||||
&cx.global::<GlobalColors>().0
|
||||
}
|
||||
}
|
||||
|
||||
/// Get [Colors] from the global state
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GlobalColors(pub Arc<Colors>);
|
||||
|
||||
impl Deref for GlobalColors {
|
||||
type Target = Arc<Colors>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Global for GlobalColors {}
|
||||
|
||||
/// Implement this trait to allow global [Color] access via `cx.default_colors()`.
|
||||
pub trait DefaultColors {
|
||||
/// Returns the default [`gpui::Colors`]
|
||||
fn default_colors(&self) -> &Arc<Colors>;
|
||||
}
|
||||
|
||||
impl DefaultColors for App {
|
||||
fn default_colors(&self) -> &Arc<Colors> {
|
||||
&self.global::<GlobalColors>().0
|
||||
}
|
||||
}
|
||||
|
||||
/// The appearance of the base GPUI colors, used to style GPUI elements
|
||||
///
|
||||
/// Varies based on the system's current [`WindowAppearance`].
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DefaultAppearance {
|
||||
/// Use the set of colors for light appearances.
|
||||
#[default]
|
||||
Light,
|
||||
/// Use the set of colors for dark appearances.
|
||||
Dark,
|
||||
}
|
||||
|
||||
impl From<WindowAppearance> for DefaultAppearance {
|
||||
fn from(appearance: WindowAppearance) -> Self {
|
||||
match appearance {
|
||||
WindowAppearance::Light | WindowAppearance::VibrantLight => Self::Light,
|
||||
WindowAppearance::Dark | WindowAppearance::VibrantDark => Self::Dark,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
use crate::{Hsla, Rgba, WindowAppearance, rgb};
|
||||
|
||||
/// The appearance of the base GPUI colors, used to style GPUI elements
|
||||
///
|
||||
/// Varies based on the system's current [`WindowAppearance`].
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DefaultThemeAppearance {
|
||||
/// Use the set of colors for light appearances.
|
||||
#[default]
|
||||
Light,
|
||||
/// Use the set of colors for dark appearances.
|
||||
Dark,
|
||||
}
|
||||
|
||||
impl From<WindowAppearance> for DefaultThemeAppearance {
|
||||
fn from(appearance: WindowAppearance) -> Self {
|
||||
match appearance {
|
||||
WindowAppearance::Light | WindowAppearance::VibrantLight => Self::Light,
|
||||
WindowAppearance::Dark | WindowAppearance::VibrantDark => Self::Dark,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the default colors for the given appearance.
|
||||
pub fn colors(appearance: DefaultThemeAppearance) -> DefaultColors {
|
||||
match appearance {
|
||||
DefaultThemeAppearance::Light => DefaultColors::light(),
|
||||
DefaultThemeAppearance::Dark => DefaultColors::dark(),
|
||||
}
|
||||
}
|
||||
|
||||
/// A collection of colors.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct DefaultColors {
|
||||
text: Rgba,
|
||||
selected_text: Rgba,
|
||||
background: Rgba,
|
||||
disabled: Rgba,
|
||||
selected: Rgba,
|
||||
border: Rgba,
|
||||
separator: Rgba,
|
||||
container: Rgba,
|
||||
}
|
||||
|
||||
impl DefaultColors {
|
||||
/// Returns the default dark colors.
|
||||
pub fn dark() -> Self {
|
||||
Self {
|
||||
text: rgb(0xffffff),
|
||||
selected_text: rgb(0xffffff),
|
||||
disabled: rgb(0x565656),
|
||||
selected: rgb(0x2457ca),
|
||||
background: rgb(0x222222),
|
||||
border: rgb(0x000000),
|
||||
separator: rgb(0xd9d9d9),
|
||||
container: rgb(0x262626),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the default light colors.
|
||||
pub fn light() -> Self {
|
||||
Self {
|
||||
text: rgb(0x252525),
|
||||
selected_text: rgb(0xffffff),
|
||||
background: rgb(0xffffff),
|
||||
disabled: rgb(0xb0b0b0),
|
||||
selected: rgb(0x2a63d9),
|
||||
border: rgb(0xd9d9d9),
|
||||
separator: rgb(0xe6e6e6),
|
||||
container: rgb(0xf4f5f5),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A default GPUI color.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::EnumIter)]
|
||||
pub enum DefaultColor {
|
||||
/// Text color
|
||||
Text,
|
||||
/// Selected text color
|
||||
SelectedText,
|
||||
/// Background color
|
||||
Background,
|
||||
/// Disabled color
|
||||
Disabled,
|
||||
/// Selected color
|
||||
Selected,
|
||||
/// Border color
|
||||
Border,
|
||||
/// Separator color
|
||||
Separator,
|
||||
/// Container color
|
||||
Container,
|
||||
}
|
||||
|
||||
impl DefaultColor {
|
||||
/// Returns the RGBA color for the given color type.
|
||||
pub fn color(&self, colors: &DefaultColors) -> Rgba {
|
||||
match self {
|
||||
DefaultColor::Text => colors.text,
|
||||
DefaultColor::SelectedText => colors.selected_text,
|
||||
DefaultColor::Background => colors.background,
|
||||
DefaultColor::Disabled => colors.disabled,
|
||||
DefaultColor::Selected => colors.selected,
|
||||
DefaultColor::Border => colors.border,
|
||||
DefaultColor::Separator => colors.separator,
|
||||
DefaultColor::Container => colors.container,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the HSLA color for the given color type.
|
||||
pub fn hsla(&self, colors: &DefaultColors) -> Hsla {
|
||||
self.color(colors).into()
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
mod anchored;
|
||||
mod animation;
|
||||
mod canvas;
|
||||
mod common;
|
||||
mod deferred;
|
||||
mod div;
|
||||
mod image_cache;
|
||||
|
@ -15,7 +14,6 @@ mod uniform_list;
|
|||
pub use anchored::*;
|
||||
pub use animation::*;
|
||||
pub use canvas::*;
|
||||
pub use common::*;
|
||||
pub use deferred::*;
|
||||
pub use div::*;
|
||||
pub use image_cache::*;
|
||||
|
|
|
@ -73,6 +73,8 @@ mod asset_cache;
|
|||
mod assets;
|
||||
mod bounds_tree;
|
||||
mod color;
|
||||
/// The default colors used by GPUI.
|
||||
pub mod colors;
|
||||
mod element;
|
||||
mod elements;
|
||||
mod executor;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use gpui::{
|
||||
AnyElement, App, DefaultColor, DefaultColors, Div, SharedString, Window, div, prelude::*, px,
|
||||
rems,
|
||||
AnyElement, App, Div, SharedString, Window, colors::DefaultColors, div, prelude::*, px, rems,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use smallvec::SmallVec;
|
||||
|
@ -8,9 +7,7 @@ use smallvec::SmallVec;
|
|||
pub struct Story {}
|
||||
|
||||
impl Story {
|
||||
pub fn container() -> gpui::Stateful<Div> {
|
||||
let colors = DefaultColors::light();
|
||||
|
||||
pub fn container(cx: &App) -> gpui::Stateful<Div> {
|
||||
div()
|
||||
.id("story_container")
|
||||
.overflow_y_scroll()
|
||||
|
@ -18,84 +15,66 @@ impl Story {
|
|||
.min_h_full()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.text_color(DefaultColor::Text.hsla(&colors))
|
||||
.bg(DefaultColor::Background.hsla(&colors))
|
||||
.text_color(cx.default_colors().text)
|
||||
.bg(cx.default_colors().background)
|
||||
}
|
||||
|
||||
pub fn title(title: impl Into<SharedString>) -> impl Element {
|
||||
let colors = DefaultColors::light();
|
||||
|
||||
pub fn title(title: impl Into<SharedString>, cx: &App) -> impl Element {
|
||||
div()
|
||||
.text_xs()
|
||||
.text_color(DefaultColor::Text.hsla(&colors))
|
||||
.text_color(cx.default_colors().text)
|
||||
.child(title.into())
|
||||
}
|
||||
|
||||
pub fn title_for<T>() -> impl Element {
|
||||
Self::title(std::any::type_name::<T>())
|
||||
pub fn title_for<T>(cx: &App) -> impl Element {
|
||||
Self::title(std::any::type_name::<T>(), cx)
|
||||
}
|
||||
|
||||
pub fn section() -> Div {
|
||||
let colors = DefaultColors::light();
|
||||
|
||||
pub fn section(cx: &App) -> Div {
|
||||
div()
|
||||
.p_4()
|
||||
.m_4()
|
||||
.border_1()
|
||||
.border_color(DefaultColor::Separator.hsla(&colors))
|
||||
.border_color(cx.default_colors().separator)
|
||||
}
|
||||
|
||||
pub fn section_title() -> Div {
|
||||
let colors = DefaultColors::light();
|
||||
|
||||
div().text_lg().text_color(DefaultColor::Text.hsla(&colors))
|
||||
pub fn section_title(cx: &App) -> Div {
|
||||
div().text_lg().text_color(cx.default_colors().text)
|
||||
}
|
||||
|
||||
pub fn group() -> Div {
|
||||
let colors = DefaultColors::light();
|
||||
div().my_2().bg(DefaultColor::Container.hsla(&colors))
|
||||
pub fn group(cx: &App) -> Div {
|
||||
div().my_2().bg(cx.default_colors().container)
|
||||
}
|
||||
|
||||
pub fn code_block(code: impl Into<SharedString>) -> Div {
|
||||
let colors = DefaultColors::light();
|
||||
|
||||
pub fn code_block(code: impl Into<SharedString>, cx: &App) -> Div {
|
||||
div()
|
||||
.size_full()
|
||||
.p_2()
|
||||
.max_w(rems(36.))
|
||||
.bg(DefaultColor::Container.hsla(&colors))
|
||||
.bg(cx.default_colors().container)
|
||||
.rounded_sm()
|
||||
.text_sm()
|
||||
.text_color(DefaultColor::Text.hsla(&colors))
|
||||
.text_color(cx.default_colors().text)
|
||||
.overflow_hidden()
|
||||
.child(code.into())
|
||||
}
|
||||
|
||||
pub fn divider() -> Div {
|
||||
let colors = DefaultColors::light();
|
||||
|
||||
div()
|
||||
.my_2()
|
||||
.h(px(1.))
|
||||
.bg(DefaultColor::Separator.hsla(&colors))
|
||||
pub fn divider(cx: &App) -> Div {
|
||||
div().my_2().h(px(1.)).bg(cx.default_colors().separator)
|
||||
}
|
||||
|
||||
pub fn description(description: impl Into<SharedString>) -> impl Element {
|
||||
let colors = DefaultColors::light();
|
||||
|
||||
pub fn description(description: impl Into<SharedString>, cx: &App) -> impl Element {
|
||||
div()
|
||||
.text_sm()
|
||||
.text_color(DefaultColor::Text.hsla(&colors))
|
||||
.text_color(cx.default_colors().text)
|
||||
.min_w_96()
|
||||
.child(description.into())
|
||||
}
|
||||
|
||||
pub fn label(label: impl Into<SharedString>) -> impl Element {
|
||||
let colors = DefaultColors::light();
|
||||
|
||||
pub fn label(label: impl Into<SharedString>, cx: &App) -> impl Element {
|
||||
div()
|
||||
.text_xs()
|
||||
.text_color(DefaultColor::Text.hsla(&colors))
|
||||
.text_color(cx.default_colors().text)
|
||||
.child(label.into())
|
||||
}
|
||||
|
||||
|
@ -135,8 +114,8 @@ impl StoryItem {
|
|||
}
|
||||
|
||||
impl RenderOnce for StoryItem {
|
||||
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
|
||||
let colors = DefaultColors::light();
|
||||
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let colors = cx.default_colors();
|
||||
|
||||
div()
|
||||
.my_2()
|
||||
|
@ -148,20 +127,20 @@ impl RenderOnce for StoryItem {
|
|||
.px_2()
|
||||
.w_1_2()
|
||||
.min_h_px()
|
||||
.child(Story::label(self.label))
|
||||
.child(Story::label(self.label, cx))
|
||||
.child(
|
||||
div()
|
||||
.rounded_sm()
|
||||
.bg(DefaultColor::Background.hsla(&colors))
|
||||
.bg(colors.background)
|
||||
.border_1()
|
||||
.border_color(DefaultColor::Border.hsla(&colors))
|
||||
.border_color(colors.border)
|
||||
.py_1()
|
||||
.px_2()
|
||||
.overflow_hidden()
|
||||
.child(self.item),
|
||||
)
|
||||
.when_some(self.description, |this, description| {
|
||||
this.child(Story::description(description))
|
||||
this.child(Story::description(description, cx))
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
|
@ -171,8 +150,8 @@ impl RenderOnce for StoryItem {
|
|||
.w_1_2()
|
||||
.min_h_px()
|
||||
.when_some(self.usage, |this, usage| {
|
||||
this.child(Story::label("Example Usage"))
|
||||
.child(Story::code_block(usage))
|
||||
this.child(Story::label("Example Usage", cx))
|
||||
.child(Story::code_block(usage, cx))
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
@ -205,21 +184,21 @@ impl StorySection {
|
|||
}
|
||||
|
||||
impl RenderOnce for StorySection {
|
||||
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
|
||||
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let children: SmallVec<[AnyElement; 2]> = SmallVec::from_iter(Itertools::intersperse_with(
|
||||
self.children.into_iter(),
|
||||
|| Story::divider().into_any_element(),
|
||||
|| Story::divider(cx).into_any_element(),
|
||||
));
|
||||
|
||||
Story::section()
|
||||
Story::section(cx)
|
||||
// Section title
|
||||
.py_2()
|
||||
// Section description
|
||||
.when_some(self.description.clone(), |section, description| {
|
||||
section.child(Story::description(description))
|
||||
section.child(Story::description(description, cx))
|
||||
})
|
||||
.child(div().flex().flex_col().gap_2().children(children))
|
||||
.child(Story::divider())
|
||||
.child(Story::divider(cx))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
mod auto_height_editor;
|
||||
mod cursor;
|
||||
mod default_colors;
|
||||
mod focus;
|
||||
mod kitchen_sink;
|
||||
mod overflow_scroll;
|
||||
|
@ -12,7 +11,6 @@ mod with_rem_size;
|
|||
|
||||
pub use auto_height_editor::*;
|
||||
pub use cursor::*;
|
||||
pub use default_colors::*;
|
||||
pub use focus::*;
|
||||
pub use kitchen_sink::*;
|
||||
pub use overflow_scroll::*;
|
||||
|
|
|
@ -5,7 +5,7 @@ use ui::prelude::*;
|
|||
pub struct CursorStory;
|
||||
|
||||
impl Render for CursorStory {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let all_cursors: [(&str, Box<dyn Fn(Stateful<Div>) -> Stateful<Div>>); 19] = [
|
||||
(
|
||||
"cursor_default",
|
||||
|
@ -85,10 +85,10 @@ impl Render for CursorStory {
|
|||
),
|
||||
];
|
||||
|
||||
Story::container()
|
||||
Story::container(cx)
|
||||
.flex()
|
||||
.gap_1()
|
||||
.child(Story::title("cursor"))
|
||||
.child(Story::title("cursor", cx))
|
||||
.children(all_cursors.map(|(name, apply_cursor)| {
|
||||
div().gap_1().flex().text_color(gpui::white()).child(
|
||||
div()
|
||||
|
@ -102,7 +102,7 @@ impl Render for CursorStory {
|
|||
.bg(gpui::red())
|
||||
.active(|style| style.bg(gpui::green()))
|
||||
.text_sm()
|
||||
.child(Story::label(name)),
|
||||
.child(Story::label(name, cx)),
|
||||
)
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
use gpui::{
|
||||
App, Context, DefaultColor, DefaultThemeAppearance, Entity, Hsla, Render, Window, colors, div,
|
||||
prelude::*,
|
||||
};
|
||||
use story::Story;
|
||||
use strum::IntoEnumIterator;
|
||||
use ui::{ActiveTheme, h_flex};
|
||||
|
||||
pub struct DefaultColorsStory;
|
||||
|
||||
impl DefaultColorsStory {
|
||||
pub fn model(cx: &mut App) -> Entity<Self> {
|
||||
cx.new(|_| Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for DefaultColorsStory {
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let appearances = [DefaultThemeAppearance::Light, DefaultThemeAppearance::Dark];
|
||||
|
||||
Story::container()
|
||||
.child(Story::title("Default Colors"))
|
||||
.children(appearances.iter().map(|&appearance| {
|
||||
let colors = colors(appearance);
|
||||
let color_types = DefaultColor::iter()
|
||||
.map(|color| {
|
||||
let name = format!("{:?}", color);
|
||||
let rgba = color.hsla(&colors);
|
||||
(name, rgba)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap_4()
|
||||
.p_4()
|
||||
.child(Story::label(format!("{:?} Appearance", appearance)))
|
||||
.children(color_types.iter().map(|(name, color)| {
|
||||
let color: Hsla = *color;
|
||||
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_2()
|
||||
.child(
|
||||
div()
|
||||
.w_12()
|
||||
.h_12()
|
||||
.bg(color)
|
||||
.border_1()
|
||||
.border_color(cx.theme().colors().border),
|
||||
)
|
||||
.child(Story::label(format!("{}: {:?}", name, color.clone())))
|
||||
}))
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child(
|
||||
h_flex()
|
||||
.bg(DefaultColor::Background.hsla(&colors))
|
||||
.h_8()
|
||||
.p_2()
|
||||
.text_sm()
|
||||
.text_color(DefaultColor::Text.hsla(&colors))
|
||||
.child("Default Text"),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.bg(DefaultColor::Container.hsla(&colors))
|
||||
.h_8()
|
||||
.p_2()
|
||||
.text_sm()
|
||||
.text_color(DefaultColor::Text.hsla(&colors))
|
||||
.child("Text on Container"),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.bg(DefaultColor::Selected.hsla(&colors))
|
||||
.h_8()
|
||||
.p_2()
|
||||
.text_sm()
|
||||
.text_color(DefaultColor::SelectedText.hsla(&colors))
|
||||
.child("Selected Text"),
|
||||
),
|
||||
)
|
||||
}))
|
||||
}
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
use std::fmt::format;
|
||||
|
||||
use gpui::{
|
||||
colors, div, prelude::*, uniform_list, DefaultColor, DefaultThemeAppearance, Hsla, Render,
|
||||
DefaultColor, DefaultThemeAppearance, Hsla, Render, colors, div, prelude::*, uniform_list,
|
||||
};
|
||||
use story::Story;
|
||||
use strum::IntoEnumIterator;
|
||||
use ui::{
|
||||
h_flex, px, v_flex, AbsoluteLength, ActiveTheme, Color, DefiniteLength, Label, LabelCommon,
|
||||
AbsoluteLength, ActiveTheme, Color, DefiniteLength, Label, LabelCommon, h_flex, px, v_flex,
|
||||
};
|
||||
|
||||
const LENGTH: usize = 100;
|
||||
|
@ -34,7 +34,7 @@ impl IndentGuidesStory {
|
|||
|
||||
impl Render for IndentGuidesStory {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container()
|
||||
Story::container(cx)
|
||||
.child(Story::title("Indent guides"))
|
||||
.child(
|
||||
v_flex().size_full().child(
|
||||
|
|
|
@ -19,11 +19,11 @@ impl Render for KitchenSinkStory {
|
|||
.map(|selector| selector.story(window, cx))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Story::container()
|
||||
Story::container(cx)
|
||||
.id("kitchen-sink")
|
||||
.overflow_y_scroll()
|
||||
.child(Story::title("Kitchen Sink"))
|
||||
.child(Story::label("Components"))
|
||||
.child(Story::title("Kitchen Sink", cx))
|
||||
.child(Story::label("Components", cx))
|
||||
.child(div().flex().flex_col().children(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.
|
||||
|
|
|
@ -6,10 +6,10 @@ use ui::prelude::*;
|
|||
pub struct OverflowScrollStory;
|
||||
|
||||
impl Render for OverflowScrollStory {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container()
|
||||
.child(Story::title("Overflow Scroll"))
|
||||
.child(Story::label("`overflow_x_scroll`"))
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container(cx)
|
||||
.child(Story::title("Overflow Scroll", cx))
|
||||
.child(Story::label("`overflow_x_scroll`", cx))
|
||||
.child(
|
||||
h_flex()
|
||||
.id("overflow_x_scroll")
|
||||
|
@ -22,7 +22,7 @@ impl Render for OverflowScrollStory {
|
|||
.child(SharedString::from(format!("Child {}", i + 1)))
|
||||
})),
|
||||
)
|
||||
.child(Story::label("`overflow_y_scroll`"))
|
||||
.child(Story::label("`overflow_y_scroll`", cx))
|
||||
.child(
|
||||
v_flex()
|
||||
.w_full()
|
||||
|
|
|
@ -14,9 +14,9 @@ impl TextStory {
|
|||
}
|
||||
|
||||
impl Render for TextStory {
|
||||
fn render(&mut self, window: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container()
|
||||
.child(Story::title("Text"))
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container(cx)
|
||||
.child(Story::title("Text", cx))
|
||||
.children(vec![
|
||||
StorySection::new()
|
||||
.child(
|
||||
|
|
|
@ -6,8 +6,8 @@ use ui::prelude::*;
|
|||
pub struct ViewportUnitsStory;
|
||||
|
||||
impl Render for ViewportUnitsStory {
|
||||
fn render(&mut self, window: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container().child(
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container(cx).child(
|
||||
div()
|
||||
.flex()
|
||||
.flex_row()
|
||||
|
|
|
@ -6,8 +6,8 @@ use ui::{prelude::*, utils::WithRemSize};
|
|||
pub struct WithRemSizeStory;
|
||||
|
||||
impl Render for WithRemSizeStory {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container().child(
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container(cx).child(
|
||||
Example::new(16., gpui::red())
|
||||
.child(
|
||||
Example::new(24., gpui::green())
|
||||
|
|
|
@ -17,7 +17,6 @@ pub enum ComponentStory {
|
|||
CollabNotification,
|
||||
ContextMenu,
|
||||
Cursor,
|
||||
DefaultColors,
|
||||
Focus,
|
||||
IconButton,
|
||||
Keybinding,
|
||||
|
@ -47,7 +46,6 @@ impl ComponentStory {
|
|||
.into(),
|
||||
Self::ContextMenu => cx.new(|_| ui::ContextMenuStory).into(),
|
||||
Self::Cursor => cx.new(|_| crate::stories::CursorStory).into(),
|
||||
Self::DefaultColors => DefaultColorsStory::model(cx).into(),
|
||||
Self::Focus => FocusStory::model(window, cx).into(),
|
||||
Self::IconButton => cx.new(|_| ui::IconButtonStory).into(),
|
||||
Self::Keybinding => cx.new(|_| ui::KeybindingStory).into(),
|
||||
|
|
|
@ -18,9 +18,9 @@ impl ApplicationMenuStory {
|
|||
}
|
||||
|
||||
impl Render for ApplicationMenuStory {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container()
|
||||
.child(Story::title_for::<ApplicationMenu>())
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<ApplicationMenu>(cx))
|
||||
.child(StorySection::new().child(StoryItem::new(
|
||||
"Application Menu",
|
||||
h_flex().child(self.menu.clone()),
|
||||
|
|
|
@ -26,8 +26,8 @@ fn build_menu(
|
|||
pub struct ContextMenuStory;
|
||||
|
||||
impl Render for ContextMenuStory {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container()
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container(cx)
|
||||
.on_action(|_: &PrintCurrentDate, _, _| {
|
||||
println!("printing unix time!");
|
||||
if let Ok(unix_time) = std::time::UNIX_EPOCH.elapsed() {
|
||||
|
|
|
@ -7,9 +7,9 @@ use crate::prelude::*;
|
|||
pub struct DisclosureStory;
|
||||
|
||||
impl Render for DisclosureStory {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container()
|
||||
.child(Story::title_for::<Disclosure>())
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<Disclosure>(cx))
|
||||
.child(Story::label("Toggled"))
|
||||
.child(Disclosure::new("toggled", true))
|
||||
.child(Story::label("Not Toggled"))
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{IconButtonShape, Tooltip, prelude::*};
|
|||
pub struct IconButtonStory;
|
||||
|
||||
impl Render for IconButtonStory {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let default_button = StoryItem::new(
|
||||
"Default",
|
||||
IconButton::new("default_icon_button", IconName::Hash),
|
||||
|
@ -113,8 +113,8 @@ impl Render for IconButtonStory {
|
|||
selected_with_tooltip_button,
|
||||
];
|
||||
|
||||
Story::container()
|
||||
.child(Story::title_for::<IconButton>())
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<IconButton>(cx))
|
||||
.child(StorySection::new().children(buttons))
|
||||
.child(
|
||||
StorySection::new().child(StoryItem::new(
|
||||
|
|
|
@ -15,11 +15,11 @@ impl Render for KeybindingStory {
|
|||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let all_modifier_permutations = ["ctrl", "alt", "cmd", "shift"].into_iter().permutations(2);
|
||||
|
||||
Story::container()
|
||||
.child(Story::title_for::<KeyBinding>())
|
||||
.child(Story::label("Single Key"))
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<KeyBinding>(cx))
|
||||
.child(Story::label("Single Key", cx))
|
||||
.child(KeyBinding::new(binding("Z"), cx))
|
||||
.child(Story::label("Single Key with Modifier"))
|
||||
.child(Story::label("Single Key with Modifier", cx))
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
|
@ -29,7 +29,7 @@ impl Render for KeybindingStory {
|
|||
.child(KeyBinding::new(binding("cmd-c"), cx))
|
||||
.child(KeyBinding::new(binding("shift-c"), cx)),
|
||||
)
|
||||
.child(Story::label("Single Key with Modifier (Permuted)"))
|
||||
.child(Story::label("Single Key with Modifier (Permuted)", cx))
|
||||
.child(
|
||||
div().flex().flex_col().children(
|
||||
all_modifier_permutations
|
||||
|
@ -46,33 +46,33 @@ impl Render for KeybindingStory {
|
|||
}),
|
||||
),
|
||||
)
|
||||
.child(Story::label("Single Key with All Modifiers"))
|
||||
.child(Story::label("Single Key with All Modifiers", cx))
|
||||
.child(KeyBinding::new(binding("ctrl-alt-cmd-shift-z"), cx))
|
||||
.child(Story::label("Chord"))
|
||||
.child(Story::label("Chord", cx))
|
||||
.child(KeyBinding::new(binding("a z"), cx))
|
||||
.child(Story::label("Chord with Modifier"))
|
||||
.child(Story::label("Chord with Modifier", cx))
|
||||
.child(KeyBinding::new(binding("ctrl-a shift-z"), cx))
|
||||
.child(KeyBinding::new(binding("fn-s"), cx))
|
||||
.child(Story::label("Single Key with All Modifiers (Linux)"))
|
||||
.child(Story::label("Single Key with All Modifiers (Linux)", cx))
|
||||
.child(
|
||||
KeyBinding::new(binding("ctrl-alt-cmd-shift-z"), cx)
|
||||
.platform_style(PlatformStyle::Linux),
|
||||
)
|
||||
.child(Story::label("Chord (Linux)"))
|
||||
.child(Story::label("Chord (Linux)", cx))
|
||||
.child(KeyBinding::new(binding("a z"), cx).platform_style(PlatformStyle::Linux))
|
||||
.child(Story::label("Chord with Modifier (Linux)"))
|
||||
.child(Story::label("Chord with Modifier (Linux)", cx))
|
||||
.child(
|
||||
KeyBinding::new(binding("ctrl-a shift-z"), cx).platform_style(PlatformStyle::Linux),
|
||||
)
|
||||
.child(KeyBinding::new(binding("fn-s"), cx).platform_style(PlatformStyle::Linux))
|
||||
.child(Story::label("Single Key with All Modifiers (Windows)"))
|
||||
.child(Story::label("Single Key with All Modifiers (Windows)", cx))
|
||||
.child(
|
||||
KeyBinding::new(binding("ctrl-alt-cmd-shift-z"), cx)
|
||||
.platform_style(PlatformStyle::Windows),
|
||||
)
|
||||
.child(Story::label("Chord (Windows)"))
|
||||
.child(Story::label("Chord (Windows)", cx))
|
||||
.child(KeyBinding::new(binding("a z"), cx).platform_style(PlatformStyle::Windows))
|
||||
.child(Story::label("Chord with Modifier (Windows)"))
|
||||
.child(Story::label("Chord with Modifier (Windows)", cx))
|
||||
.child(
|
||||
KeyBinding::new(binding("ctrl-a shift-z"), cx)
|
||||
.platform_style(PlatformStyle::Windows),
|
||||
|
|
|
@ -7,17 +7,17 @@ use crate::{ListHeader, ListSeparator, ListSubHeader, prelude::*};
|
|||
pub struct ListStory;
|
||||
|
||||
impl Render for ListStory {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container()
|
||||
.child(Story::title_for::<List>())
|
||||
.child(Story::label("Default"))
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<List>(cx))
|
||||
.child(Story::label("Default", cx))
|
||||
.child(
|
||||
List::new()
|
||||
.child(ListItem::new("apple").child("Apple"))
|
||||
.child(ListItem::new("banana").child("Banana"))
|
||||
.child(ListItem::new("cherry").child("Cherry")),
|
||||
)
|
||||
.child(Story::label("With sections"))
|
||||
.child(Story::label("With sections", cx))
|
||||
.child(
|
||||
List::new()
|
||||
.header(ListHeader::new("Produce"))
|
||||
|
|
|
@ -7,20 +7,20 @@ use crate::{IconName, ListHeader};
|
|||
pub struct ListHeaderStory;
|
||||
|
||||
impl Render for ListHeaderStory {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container()
|
||||
.child(Story::title_for::<ListHeader>())
|
||||
.child(Story::label("Default"))
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<ListHeader>(cx))
|
||||
.child(Story::label("Default", cx))
|
||||
.child(ListHeader::new("Section 1"))
|
||||
.child(Story::label("With left icon"))
|
||||
.child(Story::label("With left icon", cx))
|
||||
.child(ListHeader::new("Section 2").start_slot(Icon::new(IconName::Bell)))
|
||||
.child(Story::label("With left icon and meta"))
|
||||
.child(Story::label("With left icon and meta", cx))
|
||||
.child(
|
||||
ListHeader::new("Section 3")
|
||||
.start_slot(Icon::new(IconName::BellOff))
|
||||
.end_slot(IconButton::new("action_1", IconName::Bolt)),
|
||||
)
|
||||
.child(Story::label("With multiple meta"))
|
||||
.child(Story::label("With multiple meta", cx))
|
||||
.child(
|
||||
ListHeader::new("Section 4")
|
||||
.end_slot(IconButton::new("action_1", IconName::Bolt))
|
||||
|
|
|
@ -10,12 +10,12 @@ pub struct ListItemStory;
|
|||
|
||||
impl Render for ListItemStory {
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container()
|
||||
Story::container(cx)
|
||||
.bg(cx.theme().colors().background)
|
||||
.child(Story::title_for::<ListItem>())
|
||||
.child(Story::label("Default"))
|
||||
.child(Story::title_for::<ListItem>(cx))
|
||||
.child(Story::label("Default", cx))
|
||||
.child(ListItem::new("hello_world").child("Hello, world!"))
|
||||
.child(Story::label("Inset"))
|
||||
.child(Story::label("Inset", cx))
|
||||
.child(
|
||||
ListItem::new("inset_list_item")
|
||||
.inset(true)
|
||||
|
@ -31,7 +31,7 @@ impl Render for ListItemStory {
|
|||
.color(Color::Muted),
|
||||
),
|
||||
)
|
||||
.child(Story::label("With start slot icon"))
|
||||
.child(Story::label("With start slot icon", cx))
|
||||
.child(
|
||||
ListItem::new("with start slot_icon")
|
||||
.child("Hello, world!")
|
||||
|
@ -41,7 +41,7 @@ impl Render for ListItemStory {
|
|||
.color(Color::Muted),
|
||||
),
|
||||
)
|
||||
.child(Story::label("With start slot avatar"))
|
||||
.child(Story::label("With start slot avatar", cx))
|
||||
.child(
|
||||
ListItem::new("with_start slot avatar")
|
||||
.child("Hello, world!")
|
||||
|
@ -49,7 +49,7 @@ impl Render for ListItemStory {
|
|||
"https://avatars.githubusercontent.com/u/1714999?v=4",
|
||||
)),
|
||||
)
|
||||
.child(Story::label("With end slot"))
|
||||
.child(Story::label("With end slot", cx))
|
||||
.child(
|
||||
ListItem::new("with_left_avatar")
|
||||
.child("Hello, world!")
|
||||
|
@ -57,7 +57,7 @@ impl Render for ListItemStory {
|
|||
"https://avatars.githubusercontent.com/u/1714999?v=4",
|
||||
)),
|
||||
)
|
||||
.child(Story::label("With end hover slot"))
|
||||
.child(Story::label("With end hover slot", cx))
|
||||
.child(
|
||||
ListItem::new("with_end_hover_slot")
|
||||
.child("Hello, world!")
|
||||
|
@ -84,13 +84,13 @@ impl Render for ListItemStory {
|
|||
"https://avatars.githubusercontent.com/u/1714999?v=4",
|
||||
)),
|
||||
)
|
||||
.child(Story::label("With `on_click`"))
|
||||
.child(Story::label("With `on_click`", cx))
|
||||
.child(ListItem::new("with_on_click").child("Click me").on_click(
|
||||
|_event, _window, _cx| {
|
||||
println!("Clicked!");
|
||||
},
|
||||
))
|
||||
.child(Story::label("With `on_secondary_mouse_down`"))
|
||||
.child(Story::label("With `on_secondary_mouse_down`", cx))
|
||||
.child(
|
||||
ListItem::new("with_on_secondary_mouse_down")
|
||||
.child("Right click me")
|
||||
|
@ -98,7 +98,10 @@ impl Render for ListItemStory {
|
|||
println!("Right mouse down!");
|
||||
}),
|
||||
)
|
||||
.child(Story::label("With overflowing content in the `end_slot`"))
|
||||
.child(Story::label(
|
||||
"With overflowing content in the `end_slot`",
|
||||
cx,
|
||||
))
|
||||
.child(
|
||||
ListItem::new("with_overflowing_content_in_end_slot")
|
||||
.child("An excerpt")
|
||||
|
@ -106,6 +109,7 @@ impl Render for ListItemStory {
|
|||
)
|
||||
.child(Story::label(
|
||||
"`inset` with overflowing content in the `end_slot`",
|
||||
cx,
|
||||
))
|
||||
.child(
|
||||
ListItem::new("inset_with_overflowing_content_in_end_slot")
|
||||
|
@ -115,6 +119,7 @@ impl Render for ListItemStory {
|
|||
)
|
||||
.child(Story::label(
|
||||
"`inset` with overflowing content in `children` and `end_slot`",
|
||||
cx,
|
||||
))
|
||||
.child(
|
||||
ListItem::new("inset_with_overflowing_content_in_children_and_end_slot")
|
||||
|
|
|
@ -9,12 +9,12 @@ use crate::{Indicator, Tab};
|
|||
pub struct TabStory;
|
||||
|
||||
impl Render for TabStory {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container()
|
||||
.child(Story::title_for::<Tab>())
|
||||
.child(Story::label("Default"))
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<Tab>(cx))
|
||||
.child(Story::label("Default", cx))
|
||||
.child(h_flex().child(Tab::new("tab_1").child("Tab 1")))
|
||||
.child(Story::label("With indicator"))
|
||||
.child(Story::label("With indicator", cx))
|
||||
.child(
|
||||
h_flex().child(
|
||||
Tab::new("tab_1")
|
||||
|
@ -22,7 +22,7 @@ impl Render for TabStory {
|
|||
.child("Tab 1"),
|
||||
),
|
||||
)
|
||||
.child(Story::label("With close button"))
|
||||
.child(Story::label("With close button", cx))
|
||||
.child(
|
||||
h_flex().child(
|
||||
Tab::new("tab_1")
|
||||
|
@ -37,13 +37,13 @@ impl Render for TabStory {
|
|||
.child("Tab 1"),
|
||||
),
|
||||
)
|
||||
.child(Story::label("List of tabs"))
|
||||
.child(Story::label("List of tabs", cx))
|
||||
.child(
|
||||
h_flex()
|
||||
.child(Tab::new("tab_1").child("Tab 1"))
|
||||
.child(Tab::new("tab_2").child("Tab 2")),
|
||||
)
|
||||
.child(Story::label("List of tabs with first tab selected"))
|
||||
.child(Story::label("List of tabs with first tab selected", cx))
|
||||
.child(
|
||||
h_flex()
|
||||
.child(
|
||||
|
@ -64,7 +64,7 @@ impl Render for TabStory {
|
|||
)
|
||||
.child(Tab::new("tab_4").position(TabPosition::Last).child("Tab 4")),
|
||||
)
|
||||
.child(Story::label("List of tabs with last tab selected"))
|
||||
.child(Story::label("List of tabs with last tab selected", cx))
|
||||
.child(
|
||||
h_flex()
|
||||
.child(
|
||||
|
@ -89,7 +89,7 @@ impl Render for TabStory {
|
|||
.child("Tab 4"),
|
||||
),
|
||||
)
|
||||
.child(Story::label("List of tabs with second tab selected"))
|
||||
.child(Story::label("List of tabs with second tab selected", cx))
|
||||
.child(
|
||||
h_flex()
|
||||
.child(
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{Tab, TabBar, TabPosition, prelude::*};
|
|||
pub struct TabBarStory;
|
||||
|
||||
impl Render for TabBarStory {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let tab_count = 20;
|
||||
let selected_tab_index = 3;
|
||||
|
||||
|
@ -31,9 +31,9 @@ impl Render for TabBarStory {
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Story::container()
|
||||
.child(Story::title_for::<TabBar>())
|
||||
.child(Story::label("Default"))
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<TabBar>(cx))
|
||||
.child(Story::label("Default", cx))
|
||||
.child(
|
||||
h_flex().child(
|
||||
TabBar::new("tab_bar_1")
|
||||
|
|
|
@ -6,9 +6,9 @@ use crate::{ToggleButton, prelude::*};
|
|||
pub struct ToggleButtonStory;
|
||||
|
||||
impl Render for ToggleButtonStory {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container()
|
||||
.child(Story::title_for::<ToggleButton>())
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<ToggleButton>(cx))
|
||||
.child(
|
||||
StorySection::new().child(
|
||||
StoryItem::new(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue