1#![allow(missing_docs)]
2use gpui::{svg, App, IntoElement, Rems, RenderOnce, Size, Styled, Window};
3use serde::{Deserialize, Serialize};
4use strum::{EnumIter, EnumString, IntoStaticStr};
5use ui_macros::{path_str, DerivePathStr};
6
7use crate::Color;
8
9#[derive(
10 Debug,
11 PartialEq,
12 Eq,
13 Copy,
14 Clone,
15 EnumIter,
16 EnumString,
17 IntoStaticStr,
18 Serialize,
19 Deserialize,
20 DerivePathStr,
21)]
22#[strum(serialize_all = "snake_case")]
23#[path_str(prefix = "images", suffix = ".svg")]
24pub enum VectorName {
25 ZedLogo,
26 ZedXCopilot,
27}
28
29/// A vector image, such as an SVG.
30///
31/// A [`Vector`] is different from an [`crate::Icon`] in that it is intended
32/// to be displayed at a specific size, or series of sizes, rather
33/// than conforming to the standard size of an icon.
34#[derive(IntoElement)]
35pub struct Vector {
36 path: &'static str,
37 color: Color,
38 size: Size<Rems>,
39}
40
41impl Vector {
42 /// Creates a new [`Vector`] image with the given [`VectorName`] and size.
43 pub fn new(vector: VectorName, width: Rems, height: Rems) -> Self {
44 Self {
45 path: vector.path(),
46 color: Color::default(),
47 size: Size { width, height },
48 }
49 }
50
51 /// Creates a new [`Vector`] image where the width and height are the same.
52 pub fn square(vector: VectorName, size: Rems) -> Self {
53 Self::new(vector, size, size)
54 }
55
56 /// Sets the vector color.
57 pub fn color(mut self, color: Color) -> Self {
58 self.color = color;
59 self
60 }
61
62 /// Sets the vector size.
63 pub fn size(mut self, size: impl Into<Size<Rems>>) -> Self {
64 let size = size.into();
65
66 self.size = size;
67 self
68 }
69}
70
71impl RenderOnce for Vector {
72 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
73 let width = self.size.width;
74 let height = self.size.height;
75
76 svg()
77 // By default, prevent the SVG from stretching
78 // to fill its container.
79 .flex_none()
80 .w(width)
81 .h(height)
82 .path(self.path)
83 .text_color(self.color.color(cx))
84 }
85}
86
87#[cfg(feature = "stories")]
88pub mod story {
89 use gpui::Render;
90 use story::{Story, StoryItem, StorySection};
91 use strum::IntoEnumIterator;
92
93 use crate::prelude::*;
94
95 use super::{Vector, VectorName};
96
97 pub struct VectorStory;
98
99 impl Render for VectorStory {
100 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
101 Story::container().child(StorySection::new().children(VectorName::iter().map(
102 |vector| StoryItem::new(format!("{:?}", vector), Vector::square(vector, rems(8.))),
103 )))
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn vector_path() {
114 assert_eq!(VectorName::ZedLogo.path(), "images/zed_logo.svg");
115 }
116}