use std::sync::Arc; use gpui::{App, IntoElement, Rems, RenderOnce, Size, Styled, Window, svg}; use serde::{Deserialize, Serialize}; use strum::{EnumIter, EnumString, IntoStaticStr}; use crate::Color; use crate::prelude::*; #[derive( Debug, PartialEq, Eq, Copy, Clone, EnumIter, EnumString, IntoStaticStr, Serialize, Deserialize, )] #[strum(serialize_all = "snake_case")] pub enum VectorName { ZedLogo, ZedXCopilot, Grid, AiGrid, DebuggerGrid, } impl VectorName { /// Returns the path to this vector image. pub fn path(&self) -> Arc { let file_stem: &'static str = self.into(); format!("images/{file_stem}.svg").into() } } /// A vector image, such as an SVG. /// /// A [`Vector`] is different from an [`crate::Icon`] in that it is intended /// to be displayed at a specific size, or series of sizes, rather /// than conforming to the standard size of an icon. #[derive(IntoElement, RegisterComponent)] pub struct Vector { path: Arc, color: Color, size: Size, } impl Vector { /// Creates a new [`Vector`] image with the given [`VectorName`] and size. pub fn new(vector: VectorName, width: Rems, height: Rems) -> Self { Self { path: vector.path(), color: Color::default(), size: Size { width, height }, } } /// Creates a new [`Vector`] image where the width and height are the same. pub fn square(vector: VectorName, size: Rems) -> Self { Self::new(vector, size, size) } /// Sets the vector color. pub fn color(mut self, color: Color) -> Self { self.color = color; self } /// Sets the vector size. pub fn size(mut self, size: impl Into>) -> Self { let size = size.into(); self.size = size; self } } impl RenderOnce for Vector { fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { let width = self.size.width; let height = self.size.height; svg() // By default, prevent the SVG from stretching // to fill its container. .flex_none() .w(width) .h(height) .path(self.path) .text_color(self.color.color(cx)) } } impl Component for Vector { fn scope() -> ComponentScope { ComponentScope::Images } fn name() -> &'static str { "Vector" } fn description() -> Option<&'static str> { Some("A vector image component that can be displayed at specific sizes.") } fn preview(_window: &mut Window, _cx: &mut App) -> Option { Some( v_flex() .gap_6() .children(vec![ example_group_with_title( "Basic Usage", vec![ single_example( "Default", Vector::square(VectorName::ZedLogo, rems(8.)).into_any_element(), ), single_example( "Custom Size", Vector::new(VectorName::ZedLogo, rems(12.), rems(6.)) .into_any_element(), ), ], ), example_group_with_title( "Colored", vec![ single_example( "Accent Color", Vector::square(VectorName::ZedLogo, rems(8.)) .color(Color::Accent) .into_any_element(), ), single_example( "Error Color", Vector::square(VectorName::ZedLogo, rems(8.)) .color(Color::Error) .into_any_element(), ), ], ), example_group_with_title( "Different Vectors", vec![ single_example( "Zed Logo", Vector::square(VectorName::ZedLogo, rems(8.)).into_any_element(), ), single_example( "Zed X Copilot", Vector::square(VectorName::ZedXCopilot, rems(8.)) .into_any_element(), ), ], ), ]) .into_any_element(), ) } } #[cfg(test)] mod tests { use super::*; #[test] fn vector_path() { assert_eq!(VectorName::ZedLogo.path().as_ref(), "images/zed_logo.svg"); } }