theme_preview.rs

  1#![allow(unused, dead_code)]
  2use gpui::{Hsla, Length};
  3use std::sync::Arc;
  4use theme::{Theme, ThemeRegistry};
  5use ui::{
  6    IntoElement, RenderOnce, component_prelude::Documented, prelude::*, utils::inner_corner_radius,
  7};
  8
  9/// Shows a preview of a theme as an abstract illustration
 10/// of a thumbnail-sized editor.
 11#[derive(IntoElement, RegisterComponent, Documented)]
 12pub struct ThemePreviewTile {
 13    theme: Arc<Theme>,
 14    selected: bool,
 15    seed: f32,
 16}
 17
 18impl ThemePreviewTile {
 19    pub fn new(theme: Arc<Theme>, selected: bool, seed: f32) -> Self {
 20        Self {
 21            theme,
 22            selected,
 23            seed,
 24        }
 25    }
 26
 27    pub fn selected(mut self, selected: bool) -> Self {
 28        self.selected = selected;
 29        self
 30    }
 31}
 32
 33impl RenderOnce for ThemePreviewTile {
 34    fn render(self, _window: &mut ui::Window, _cx: &mut ui::App) -> impl IntoElement {
 35        let color = self.theme.colors();
 36
 37        let root_radius = px(8.0);
 38        let root_border = px(2.0);
 39        let root_padding = px(2.0);
 40        let child_border = px(1.0);
 41        let inner_radius =
 42            inner_corner_radius(root_radius, root_border, root_padding, child_border);
 43
 44        let item_skeleton = |w: Length, h: Pixels, bg: Hsla| div().w(w).h(h).rounded_full().bg(bg);
 45
 46        let skeleton_height = px(4.);
 47
 48        let sidebar_seeded_width = |seed: f32, index: usize| {
 49            let value = (seed * 1000.0 + index as f32 * 10.0).sin() * 0.5 + 0.5;
 50            0.5 + value * 0.45
 51        };
 52
 53        let sidebar_skeleton_items = 8;
 54
 55        let sidebar_skeleton = (0..sidebar_skeleton_items)
 56            .map(|i| {
 57                let width = sidebar_seeded_width(self.seed, i);
 58                item_skeleton(
 59                    relative(width).into(),
 60                    skeleton_height,
 61                    color.text.alpha(0.45),
 62                )
 63            })
 64            .collect::<Vec<_>>();
 65
 66        let sidebar = div()
 67            .h_full()
 68            .w(relative(0.25))
 69            .border_r(px(1.))
 70            .border_color(color.border_transparent)
 71            .bg(color.panel_background)
 72            .child(
 73                div()
 74                    .p_2()
 75                    .flex()
 76                    .flex_col()
 77                    .size_full()
 78                    .gap(px(4.))
 79                    .children(sidebar_skeleton),
 80            );
 81
 82        let pseudo_code_skeleton = |theme: Arc<Theme>, seed: f32| -> AnyElement {
 83            let colors = theme.colors();
 84            let syntax = theme.syntax();
 85
 86            let keyword_color = syntax.get("keyword").color;
 87            let function_color = syntax.get("function").color;
 88            let string_color = syntax.get("string").color;
 89            let comment_color = syntax.get("comment").color;
 90            let variable_color = syntax.get("variable").color;
 91            let type_color = syntax.get("type").color;
 92            let punctuation_color = syntax.get("punctuation").color;
 93
 94            let syntax_colors = [
 95                keyword_color,
 96                function_color,
 97                string_color,
 98                variable_color,
 99                type_color,
100                punctuation_color,
101                comment_color,
102            ];
103
104            let line_width = |line_idx: usize, block_idx: usize| -> f32 {
105                let val = (seed * 100.0 + line_idx as f32 * 20.0 + block_idx as f32 * 5.0).sin()
106                    * 0.5
107                    + 0.5;
108                0.05 + val * 0.2
109            };
110
111            let indentation = |line_idx: usize| -> f32 {
112                let step = line_idx % 6;
113                if step < 3 {
114                    step as f32 * 0.1
115                } else {
116                    (5 - step) as f32 * 0.1
117                }
118            };
119
120            let pick_color = |line_idx: usize, block_idx: usize| -> Hsla {
121                let idx = ((seed * 10.0 + line_idx as f32 * 7.0 + block_idx as f32 * 3.0).sin()
122                    * 3.5)
123                    .abs() as usize
124                    % syntax_colors.len();
125                syntax_colors[idx].unwrap_or(colors.text)
126            };
127
128            let line_count = 13;
129
130            let lines = (0..line_count)
131                .map(|line_idx| {
132                    let block_count = (((seed * 30.0 + line_idx as f32 * 12.0).sin() * 0.5 + 0.5)
133                        * 3.0)
134                        .round() as usize
135                        + 2;
136
137                    let indent = indentation(line_idx);
138
139                    let blocks = (0..block_count)
140                        .map(|block_idx| {
141                            let width = line_width(line_idx, block_idx);
142                            let color = pick_color(line_idx, block_idx);
143                            item_skeleton(relative(width).into(), skeleton_height, color)
144                        })
145                        .collect::<Vec<_>>();
146
147                    h_flex().gap(px(2.)).ml(relative(indent)).children(blocks)
148                })
149                .collect::<Vec<_>>();
150
151            v_flex()
152                .size_full()
153                .p_1()
154                .gap(px(6.))
155                .children(lines)
156                .into_any_element()
157        };
158
159        let pane = div()
160            .h_full()
161            .flex_grow()
162            .flex()
163            .flex_col()
164            // .child(
165            //     div()
166            //         .w_full()
167            //         .border_color(color.border)
168            //         .border_b(px(1.))
169            //         .h(relative(0.1))
170            //         .bg(color.tab_bar_background),
171            // )
172            .child(
173                div()
174                    .size_full()
175                    .overflow_hidden()
176                    .bg(color.editor_background)
177                    .p_2()
178                    .child(pseudo_code_skeleton(self.theme.clone(), self.seed)),
179            );
180
181        let content = div().size_full().flex().child(sidebar).child(pane);
182
183        div()
184            .size_full()
185            .rounded(root_radius)
186            .p(root_padding)
187            .border(root_border)
188            .border_color(color.border_transparent)
189            .when(self.selected, |this| {
190                this.border_color(color.border_selected)
191            })
192            .child(
193                div()
194                    .size_full()
195                    .rounded(inner_radius)
196                    .border(child_border)
197                    .border_color(color.border)
198                    .bg(color.background)
199                    .child(content),
200            )
201    }
202}
203
204impl Component for ThemePreviewTile {
205    fn description() -> Option<&'static str> {
206        Some(Self::DOCS)
207    }
208
209    fn preview(_window: &mut Window, cx: &mut App) -> Option<AnyElement> {
210        let theme_registry = ThemeRegistry::global(cx);
211
212        let one_dark = theme_registry.get("One Dark");
213        let one_light = theme_registry.get("One Light");
214        let gruvbox_dark = theme_registry.get("Gruvbox Dark");
215        let gruvbox_light = theme_registry.get("Gruvbox Light");
216
217        let themes_to_preview = vec![
218            one_dark.clone().ok(),
219            one_light.clone().ok(),
220            gruvbox_dark.clone().ok(),
221            gruvbox_light.clone().ok(),
222        ]
223        .into_iter()
224        .flatten()
225        .collect::<Vec<_>>();
226
227        Some(
228            v_flex()
229                .gap_6()
230                .p_4()
231                .children({
232                    if let Some(one_dark) = one_dark.ok() {
233                        vec![example_group(vec![
234                            single_example(
235                                "Default",
236                                div()
237                                    .w(px(240.))
238                                    .h(px(180.))
239                                    .child(ThemePreviewTile::new(one_dark.clone(), false, 0.42))
240                                    .into_any_element(),
241                            ),
242                            single_example(
243                                "Selected",
244                                div()
245                                    .w(px(240.))
246                                    .h(px(180.))
247                                    .child(ThemePreviewTile::new(one_dark, true, 0.42))
248                                    .into_any_element(),
249                            ),
250                        ])]
251                    } else {
252                        vec![]
253                    }
254                })
255                .child(
256                    example_group(vec![single_example(
257                        "Default Themes",
258                        h_flex()
259                            .gap_4()
260                            .children(
261                                themes_to_preview
262                                    .iter()
263                                    .enumerate()
264                                    .map(|(i, theme)| {
265                                        div().w(px(200.)).h(px(140.)).child(ThemePreviewTile::new(
266                                            theme.clone(),
267                                            false,
268                                            0.42,
269                                        ))
270                                    })
271                                    .collect::<Vec<_>>(),
272                            )
273                            .into_any_element(),
274                    )])
275                    .grow(),
276                )
277                .into_any_element(),
278        )
279    }
280}