theme_preview.rs

  1#![allow(unused, dead_code)]
  2use gpui::{Hsla, Length};
  3use std::sync::Arc;
  4use theme::{Theme, ThemeRegistry};
  5use ui::{IntoElement, RenderOnce, prelude::*, utils::CornerSolver};
  6
  7/// Shows a preview of a theme as an abstract illustration
  8/// of a thumbnail-sized editor.
  9#[derive(IntoElement)]
 10pub struct ThemePreviewTile {
 11    theme: Arc<Theme>,
 12    selected: bool,
 13    seed: f32,
 14}
 15
 16impl ThemePreviewTile {
 17    pub fn new(theme: Arc<Theme>, selected: bool, seed: f32) -> Self {
 18        Self {
 19            theme,
 20            selected,
 21            seed,
 22        }
 23    }
 24
 25    pub fn selected(mut self, selected: bool) -> Self {
 26        self.selected = selected;
 27        self
 28    }
 29}
 30
 31impl RenderOnce for ThemePreviewTile {
 32    fn render(self, _window: &mut ui::Window, _cx: &mut ui::App) -> impl IntoElement {
 33        let color = self.theme.colors();
 34
 35        let root_radius = px(8.0);
 36        let root_border = px(2.0);
 37        let root_padding = px(0.0);
 38        let child_border = px(1.0);
 39        let inner_radius =
 40            CornerSolver::child_radius(root_radius, root_border, root_padding, child_border);
 41
 42        let item_skeleton = |w: Length, h: Pixels, bg: Hsla| div().w(w).h(h).rounded_full().bg(bg);
 43
 44        let skeleton_height = px(4.);
 45
 46        let sidebar_seeded_width = |seed: f32, index: usize| {
 47            let value = (seed * 1000.0 + index as f32 * 10.0).sin() * 0.5 + 0.5;
 48            0.5 + value * 0.45
 49        };
 50
 51        let sidebar_skeleton_items = 8;
 52
 53        let sidebar_skeleton = (0..sidebar_skeleton_items)
 54            .map(|i| {
 55                let width = sidebar_seeded_width(self.seed, i);
 56                item_skeleton(
 57                    relative(width).into(),
 58                    skeleton_height,
 59                    color.text.alpha(0.45),
 60                )
 61            })
 62            .collect::<Vec<_>>();
 63
 64        let sidebar = div()
 65            .h_full()
 66            .w(relative(0.25))
 67            .border_r(px(1.))
 68            .border_color(color.border_transparent)
 69            .bg(color.panel_background)
 70            .child(
 71                div()
 72                    .p_2()
 73                    .flex()
 74                    .flex_col()
 75                    .size_full()
 76                    .gap(px(4.))
 77                    .children(sidebar_skeleton),
 78            );
 79
 80        let pseudo_code_skeleton = |theme: Arc<Theme>, seed: f32| -> AnyElement {
 81            let colors = theme.colors();
 82            let syntax = theme.syntax();
 83
 84            let keyword_color = syntax.get("keyword").color;
 85            let function_color = syntax.get("function").color;
 86            let string_color = syntax.get("string").color;
 87            let comment_color = syntax.get("comment").color;
 88            let variable_color = syntax.get("variable").color;
 89            let type_color = syntax.get("type").color;
 90            let punctuation_color = syntax.get("punctuation").color;
 91
 92            let syntax_colors = [
 93                keyword_color,
 94                function_color,
 95                string_color,
 96                variable_color,
 97                type_color,
 98                punctuation_color,
 99                comment_color,
100            ];
101
102            let line_width = |line_idx: usize, block_idx: usize| -> f32 {
103                let val = (seed * 100.0 + line_idx as f32 * 20.0 + block_idx as f32 * 5.0).sin()
104                    * 0.5
105                    + 0.5;
106                0.05 + val * 0.2
107            };
108
109            let indentation = |line_idx: usize| -> f32 {
110                let step = line_idx % 6;
111                if step < 3 {
112                    step as f32 * 0.1
113                } else {
114                    (5 - step) as f32 * 0.1
115                }
116            };
117
118            let pick_color = |line_idx: usize, block_idx: usize| -> Hsla {
119                let idx = ((seed * 10.0 + line_idx as f32 * 7.0 + block_idx as f32 * 3.0).sin()
120                    * 3.5)
121                    .abs() as usize
122                    % syntax_colors.len();
123                syntax_colors[idx].unwrap_or(colors.text)
124            };
125
126            let line_count = 13;
127
128            let lines = (0..line_count)
129                .map(|line_idx| {
130                    let block_count = (((seed * 30.0 + line_idx as f32 * 12.0).sin() * 0.5 + 0.5)
131                        * 3.0)
132                        .round() as usize
133                        + 2;
134
135                    let indent = indentation(line_idx);
136
137                    let blocks = (0..block_count)
138                        .map(|block_idx| {
139                            let width = line_width(line_idx, block_idx);
140                            let color = pick_color(line_idx, block_idx);
141                            item_skeleton(relative(width).into(), skeleton_height, color)
142                        })
143                        .collect::<Vec<_>>();
144
145                    h_flex().gap(px(2.)).ml(relative(indent)).children(blocks)
146                })
147                .collect::<Vec<_>>();
148
149            v_flex()
150                .size_full()
151                .p_1()
152                .gap(px(6.))
153                .children(lines)
154                .into_any_element()
155        };
156
157        let pane = div()
158            .h_full()
159            .flex_grow()
160            .flex()
161            .flex_col()
162            // .child(
163            //     div()
164            //         .w_full()
165            //         .border_color(color.border)
166            //         .border_b(px(1.))
167            //         .h(relative(0.1))
168            //         .bg(color.tab_bar_background),
169            // )
170            .child(
171                div()
172                    .size_full()
173                    .overflow_hidden()
174                    .bg(color.editor_background)
175                    .p_2()
176                    .child(pseudo_code_skeleton(self.theme.clone(), self.seed)),
177            );
178
179        let content = div().size_full().flex().child(sidebar).child(pane);
180
181        div()
182            .size_full()
183            .rounded(root_radius)
184            .p(root_padding)
185            .border(root_border)
186            .border_color(color.border_transparent)
187            .when(self.selected, |this| {
188                this.border_color(color.border_selected)
189            })
190            .child(
191                div()
192                    .size_full()
193                    .rounded(inner_radius)
194                    .border(child_border)
195                    .border_color(color.border)
196                    .bg(color.background)
197                    .child(content),
198            )
199    }
200}