Compare commits

...

10 Commits

Author SHA1 Message Date
Nate Butler
e652495dbd Checkpoint 2024-12-05 21:51:15 -05:00
Nate Butler
560e084c5c add hash vectors and preview 2024-12-05 21:15:56 -05:00
Nate Butler
3c688e98dc Checkpoint 2024-12-05 16:56:57 -05:00
Nate Butler
f770538ba3 Checkpoint 2024-12-05 16:11:05 -05:00
Nate Butler
ac0eae3276 Checkpoint 2024-12-05 15:46:29 -05:00
Nate Butler
eb06378c85 Checkpoint 2024-12-05 15:19:01 -05:00
Bennet Bo Fenner
d907a698a2 Use text style from editor and calculate line height correctly
Co-Authored-by: Nate <nate@zed.dev>
2024-12-05 19:15:32 +01:00
Nate Butler
3d2f0e0d34 Checkpoint 2024-12-05 12:21:31 -05:00
Nate Butler
0e5b32d55d Checkpoint 2024-12-05 12:20:38 -05:00
Nate Butler
9d412702d7 Checkpoint 2024-12-05 11:55:37 -05:00
7 changed files with 442 additions and 8 deletions

View File

@@ -0,0 +1,20 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_787_8130)">
<mask id="mask0_787_8130" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="12" height="12">
<path d="M12 0H0V12H12V0Z" fill="white"/>
</mask>
<g mask="url(#mask0_787_8130)">
<path d="M16.5 -1.5L-3.5 18.5" stroke="black" stroke-width="2"/>
<path d="M10.5 -1.5L-9.5 18.5" stroke="black" stroke-width="2"/>
<path d="M4.5 -1.5L-15.5 18.5" stroke="black" stroke-width="2"/>
<path d="M22.5 -1.5L-1 22" stroke="black" stroke-width="2"/>
<path d="M32.5 -1.5L9.5 21.5" stroke="black" stroke-width="2"/>
<path d="M37.5 -1.5L12 24" stroke="black" stroke-width="2"/>
</g>
</g>
<defs>
<clipPath id="clip0_787_8130">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 832 B

View File

@@ -0,0 +1,20 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_787_8141)">
<mask id="mask0_787_8141" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="12" height="12">
<path d="M12 0H0V12H12V0Z" fill="white"/>
</mask>
<g mask="url(#mask0_787_8141)">
<path d="M16.5 -1.5L-3.5 18.5" stroke="black"/>
<path d="M10.5 -1.5L-9.5 18.5" stroke="black"/>
<path d="M4.5 -1.5L-15.5 18.5" stroke="black"/>
<path d="M22.5 -1.5L-1 22" stroke="black"/>
<path d="M32.5 -1.5L9.5 21.5" stroke="black" stroke-width="2"/>
<path d="M37.5 -1.5L12 24" stroke="black" stroke-width="2"/>
</g>
</g>
<defs>
<clipPath id="clip0_787_8141">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 764 B

View File

@@ -1,6 +1,7 @@
mod auto_height_editor;
mod cursor;
mod default_colors;
mod fake_editor;
mod focus;
mod kitchen_sink;
mod overflow_scroll;
@@ -13,6 +14,7 @@ mod with_rem_size;
pub use auto_height_editor::*;
pub use cursor::*;
pub use default_colors::*;
pub use fake_editor::*;
pub use focus::*;
pub use kitchen_sink::*;
pub use overflow_scroll::*;

View File

@@ -0,0 +1,318 @@
use editor::*;
use gpui::*;
use settings::Settings as _;
use theme::ThemeSettings;
use ui::*;
// const DEFAULT_LINE_HEIGHT: Pixels = Pixels(20.);
pub struct EditorPrototype {
editor: View<Editor>,
text_style: TextStyle,
elements_above: Vec<(u32, Box<dyn Fn(Pixels, &mut WindowContext) -> AnyElement>)>,
elements_below: Vec<(u32, Box<dyn Fn(Pixels, &mut WindowContext) -> AnyElement>)>,
height: Length,
}
impl EditorPrototype {
pub fn build(
cx: &mut WindowContext,
f: impl FnOnce(Self, &mut ViewContext<Self>) -> Self,
) -> View<Self> {
let theme = ThemeSettings::get_global(cx);
let line_height = rems(theme.buffer_line_height.value()).to_pixels(cx.rem_size());
let mut text_style = cx.text_style();
let refinement = TextStyleRefinement {
font_family: Some(theme.buffer_font.family.clone()),
line_height: Some(line_height.into()),
background_color: Some(gpui::transparent_black()),
..Default::default()
};
text_style.refine(&refinement);
let editor = cx.new_view(|cx| {
let mut editor = Editor::auto_height(20, cx);
editor.set_text_style_refinement(refinement);
editor.set_show_gutter(true, cx);
editor.set_show_line_numbers(true, cx);
editor
});
let mut height = Length::Auto;
editor.update(cx, |editor, cx| {
let line_count = editor.max_point(cx).row() + 1;
println!("line_count: {}", line_count.as_f32());
let line_height = line_height.0;
println!("line_height: {}", line_height);
height = px((line_count.as_f32() * line_height).round()).into();
println!("height: {:?}", height);
});
println!("final height: {:?}", height);
cx.new_view(|cx| {
cx.refresh();
f(
Self {
editor,
text_style,
elements_above: Vec::new(),
elements_below: Vec::new(),
height,
},
cx,
)
})
}
pub fn line_height(&self, cx: &ViewContext<Self>) -> Pixels {
self.text_style
.line_height
.to_pixels(self.text_style.font_size, cx.rem_size())
}
pub fn text(mut self, initial_text: &str, cx: &mut ViewContext<Self>) -> Self {
let mut height = self.height;
let line_height = self.line_height(cx);
self.editor.update(cx, |editor, cx| {
editor.set_text(initial_text, cx);
let line_count = editor.max_point(cx).row() + 1;
println!("line_count: {}", line_count.as_f32());
let line_height = line_height.0;
println!("line_height: {}", line_height);
height = px((line_count.as_f32() * line_height).round()).into();
println!("height: {:?}", height);
});
self.height = height;
println!("final height: {:?}", height);
cx.notify();
self
}
fn element_above(
mut self,
row: u32,
element_fn: impl Fn(Pixels, &mut WindowContext) -> AnyElement + 'static,
) -> Self {
self.elements_above.push((row, Box::new(element_fn)));
self
}
fn element_below(
mut self,
row: u32,
element_fn: impl Fn(Pixels, &mut WindowContext) -> AnyElement + 'static,
) -> Self {
self.elements_below.push((row, Box::new(element_fn)));
self
}
}
impl Render for EditorPrototype {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let line_height = self.line_height(cx);
div()
.relative()
.flex_shrink_0()
.w_full()
.h(self.height)
.bg(cx.theme().colors().editor_background)
.child(div().absolute().top_0().left_0().size_full().children(
self.elements_below.iter().map(|(row, element_fn)| {
div()
.absolute()
.top(px(*row as f32) * line_height)
.left_0()
.w_full()
.child(element_fn(line_height, cx))
}),
))
.child(
h_flex()
.relative()
.child(div().w(px(48.)).h_full().flex_shrink_0())
.child(div().size_full().child(self.editor.clone())),
)
.child(div().absolute().top_0().left_0().size_full().children(
self.elements_above.iter().map(|(row, element_fn)| {
div()
.absolute()
.top(px(*row as f32) * line_height)
.left_0()
.w_full()
.child(element_fn(line_height, cx))
}),
))
}
}
pub struct FakeEditorStory {
fake_editor_1: View<EditorPrototype>,
}
impl FakeEditorStory {
pub fn view(cx: &mut WindowContext) -> View<Self> {
let editor_text = r###"fn main() {
println!("Hello, World!");
let name = "Rust";
println!("Welcome to {}", name);
let x = 5;
let y = 7;
println!("{} + {} = {}", x, y, x + y);
if x < y {
println!("{} is less than {}", x, y);
}
greet("Rustacean");
}
fn greet(name: &str) {
println!("Hello, {}!", name);
}"###;
cx.new_view(|cx| {
let fake_editor_1 = EditorPrototype::build(cx, |fake_editor, cx| {
fake_editor
.text(editor_text, cx)
.element_below(3, |line_height, cx| {
let pattern_color = hsla(142. / 360., 0.68, 0.45, 0.08);
VectorPattern::single_row(
VectorName::HashPattern,
rems(line_height / cx.rem_size()),
pattern_color,
99,
)
.into_any_element()
})
.element_below(3, |line_height, _| {
let green_bg = hsla(142. / 360., 0.68, 0.45, 0.06);
div()
.id("foo")
.bg(green_bg)
.w_full()
.h(line_height)
.into_any_element()
})
.element_above(3, |line_height, _| {
h_flex()
.group("")
.relative()
.overflow_hidden()
.occlude()
.w_full()
.h(line_height)
.child(
h_flex()
.invisible()
.group_hover("", |this| this.visible())
.w(px(38.))
.items_center()
.justify_center()
.child(Checkbox::new("stage-line", false.into())),
)
.into_any_element()
})
.element_above(3, |line_height, _| {
let green_fg = hsla(142. / 360., 0.68, 0.45, 0.7);
div()
.relative()
.overflow_hidden()
.w(px(3.))
.h(line_height)
.child(
div()
.id("added-mark")
.absolute()
.top_0()
.left(px(-3.0))
.bg(green_fg)
.w(px(6.))
.rounded_sm()
.h(line_height)
.into_any_element(),
)
.into_any_element()
})
.element_below(4, |line_height, _| {
let green_bg = hsla(142. / 360., 0.68, 0.45, 0.08);
div()
.id("foo")
.bg(green_bg)
.w_full()
.h(line_height)
.into_any_element()
})
.element_above(4, |line_height, _| {
h_flex()
.group("")
.w_full()
.relative()
.overflow_hidden()
.occlude()
.h(line_height)
.child(
h_flex()
.invisible()
.group_hover("", |this| this.visible())
.w(px(38.))
.items_center()
.justify_center()
.child(Checkbox::new("stage-line", true.into())),
)
.into_any_element()
})
.element_above(4, |line_height, _| {
let green_fg = hsla(142. / 360., 0.68, 0.45, 0.7);
div()
.relative()
.overflow_hidden()
.w(px(3.))
.h(line_height)
.child(
div()
.absolute()
.top_0()
.left(px(-3.0))
.id("added-mark")
.bg(green_fg)
.w(px(6.))
.rounded_sm()
.h(line_height)
.into_any_element(),
)
.into_any_element()
})
});
Self { fake_editor_1 }
})
}
}
impl Render for FakeEditorStory {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
v_flex().size_full().bg(black()).text_sm().flex_1().child(
div().size_full().p_4().child(
v_flex()
.size_full()
.rounded_md()
.border_1()
.border_color(cx.theme().colors().border)
.bg(cx.theme().colors().background)
.child(self.fake_editor_1.clone()),
),
)
}
}

View File

@@ -24,6 +24,7 @@ pub enum ComponentStory {
Focus,
Icon,
IconButton,
FakeEditor,
Keybinding,
Label,
List,
@@ -54,6 +55,7 @@ impl ComponentStory {
Self::CollabNotification => cx
.new_view(|_| collab_ui::notifications::CollabNotificationStory)
.into(),
Self::FakeEditor => crate::stories::FakeEditorStory::view(cx).into(),
Self::ContextMenu => cx.new_view(|_| ui::ContextMenuStory).into(),
Self::Cursor => cx.new_view(|_| crate::stories::CursorStory).into(),
Self::DefaultColors => DefaultColorsStory::view(cx).into(),

View File

@@ -1,10 +1,11 @@
#![allow(missing_docs)]
use gpui::{svg, IntoElement, Rems, RenderOnce, Size, Styled, WindowContext};
use crate::prelude::*;
use gpui::{svg, Hsla, IntoElement, Rems, RenderOnce, Size, Styled, WindowContext};
use serde::{Deserialize, Serialize};
use strum::{EnumIter, EnumString, IntoStaticStr};
use ui_macros::{path_str, DerivePathStr};
use crate::Color;
use crate::{Color, ComponentPreview};
#[derive(
Debug,
@@ -22,6 +23,8 @@ use crate::Color;
#[strum(serialize_all = "snake_case")]
#[path_str(prefix = "images", suffix = ".svg")]
pub enum VectorName {
HashPattern,
HashPatternFine,
ZedLogo,
ZedXCopilot,
}
@@ -84,6 +87,38 @@ impl RenderOnce for Vector {
}
}
#[derive(IntoElement)]
pub struct VectorPattern {
vectors: Vec<Vector>,
}
impl VectorPattern {
pub fn single_row(vector: VectorName, size: Rems, color: Hsla, pattern_cols: usize) -> Self {
let vectors = (0..pattern_cols)
.map(|_| Vector::square(vector, size).color(Color::Custom(color)))
.collect();
Self { vectors }
}
pub fn multi_row(
vector: VectorName,
size: Rems,
pattern_rows: usize,
pattern_cols: usize,
) -> Self {
let vectors = (0..pattern_rows)
.flat_map(|_| (0..pattern_cols).map(|_| Vector::square(vector, size)))
.collect();
Self { vectors }
}
}
impl RenderOnce for VectorPattern {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
h_flex().children(self.vectors)
}
}
#[cfg(feature = "stories")]
pub mod story {
use gpui::Render;
@@ -114,3 +149,39 @@ mod tests {
assert_eq!(VectorName::ZedLogo.path(), "images/zed_logo.svg");
}
}
impl ComponentPreview for Vector {
fn title() -> &'static str {
"Vector"
}
fn description() -> impl Into<Option<&'static str>> {
"Vectors are scalable images such as SVGs that can be displayed at specific sizes."
}
fn examples(cx: &WindowContext) -> Vec<ComponentExampleGroup<Self>> {
vec![
example_group_with_title(
"Square Vectors",
vec![
single_example("Zed Logo", Vector::square(VectorName::ZedLogo, rems(1.))),
single_example(
"Hash Pattern",
Vector::square(VectorName::HashPattern, rems(1.)),
),
single_example(
"Fine Hash Pattern",
Vector::square(VectorName::HashPatternFine, rems(1.)),
),
],
),
example_group_with_title(
"Custom Sized Vectors",
vec![single_example(
"Wide Logo",
Vector::new(VectorName::ZedXCopilot, rems(12.), rems(4.)),
)],
),
]
}
}

View File

@@ -6,7 +6,7 @@ use ui::{
element_cell, prelude::*, string_cell, utils::calculate_contrast_ratio, AudioStatus,
Availability, Avatar, AvatarAudioStatusIndicator, AvatarAvailabilityIndicator, ButtonLike,
Checkbox, CheckboxWithLabel, ContentGroup, DecoratedIcon, ElevationIndex, Facepile,
IconDecoration, Indicator, Table, TintColor, Tooltip,
IconDecoration, Indicator, Table, TintColor, Tooltip, Vector,
};
use crate::{Item, Workspace};
@@ -510,16 +510,17 @@ impl ThemePreview {
.overflow_scroll()
.size_full()
.gap_2()
.child(ContentGroup::render_component_previews(cx))
.child(IconDecoration::render_component_previews(cx))
.child(DecoratedIcon::render_component_previews(cx))
.child(Button::render_component_previews(cx))
.child(Checkbox::render_component_previews(cx))
.child(CheckboxWithLabel::render_component_previews(cx))
.child(ContentGroup::render_component_previews(cx))
.child(DecoratedIcon::render_component_previews(cx))
.child(Facepile::render_component_previews(cx))
.child(Button::render_component_previews(cx))
.child(Indicator::render_component_previews(cx))
.child(Icon::render_component_previews(cx))
.child(IconDecoration::render_component_previews(cx))
.child(Indicator::render_component_previews(cx))
.child(Table::render_component_previews(cx))
.child(Vector::render_component_previews(cx))
.child(self.render_avatars(cx))
.child(self.render_buttons(layer, cx))
}