@@ -1,42 +1,24 @@
+use std::sync::Arc;
+
use client::TelemetrySettings;
use fs::Fs;
-use gpui::{App, Entity, IntoElement, Window};
+use gpui::{App, IntoElement, Window};
use settings::{BaseKeymap, Settings, update_settings_file};
-use theme::{Appearance, ThemeMode, ThemeName, ThemeRegistry, ThemeSelection, ThemeSettings};
+use theme::{
+ Appearance, SystemAppearance, ThemeMode, ThemeName, ThemeRegistry, ThemeSelection,
+ ThemeSettings,
+};
use ui::{
ParentElement as _, StatefulInteractiveElement, SwitchField, ToggleButtonGroup,
ToggleButtonSimple, ToggleButtonWithIcon, prelude::*, rems_from_px,
};
use vim_mode_setting::VimModeSetting;
-use crate::theme_preview::ThemePreviewTile;
+use crate::theme_preview::{ThemePreviewStyle, ThemePreviewTile};
-/// separates theme "mode" ("dark" | "light" | "system") into two separate states
-/// - appearance = "dark" | "light"
-/// - "system" true/false
-/// when system selected:
-/// - toggling between light and dark does not change theme.mode, just which variant will be changed
-/// when system not selected:
-/// - toggling between light and dark does change theme.mode
-/// selecting a theme preview will always change theme.["light" | "dark"] to the selected theme,
-///
-/// this allows for selecting a dark and light theme option regardless of whether the mode is set to system or not
-/// it does not support setting theme to a static value
-fn render_theme_section(window: &mut Window, cx: &mut App) -> impl IntoElement {
+fn render_theme_section(_window: &mut Window, cx: &mut App) -> impl IntoElement {
let theme_selection = ThemeSettings::get_global(cx).theme_selection.clone();
let system_appearance = theme::SystemAppearance::global(cx);
- let appearance_state = window.use_state(cx, |_, _cx| {
- theme_selection
- .as_ref()
- .and_then(|selection| selection.mode())
- .and_then(|mode| match mode {
- ThemeMode::System => None,
- ThemeMode::Light => Some(Appearance::Light),
- ThemeMode::Dark => Some(Appearance::Dark),
- })
- .unwrap_or(*system_appearance)
- });
- let appearance = *appearance_state.read(cx);
let theme_selection = theme_selection.unwrap_or_else(|| ThemeSelection::Dynamic {
mode: match *system_appearance {
Appearance::Light => ThemeMode::Light,
@@ -45,70 +27,13 @@ fn render_theme_section(window: &mut Window, cx: &mut App) -> impl IntoElement {
light: ThemeName("One Light".into()),
dark: ThemeName("One Dark".into()),
});
- let theme_registry = ThemeRegistry::global(cx);
-
- let current_theme_name = theme_selection.theme(appearance);
- let theme_mode = theme_selection.mode().unwrap_or_default();
-
- // let theme_mode = theme_selection.mode();
- // TODO: Clean this up once the "System" button inside the
- // toggle button group is done
-
- let selected_index = match appearance {
- Appearance::Light => 0,
- Appearance::Dark => 1,
- };
- let theme_seed = 0xBEEF as f32;
-
- const LIGHT_THEMES: [&'static str; 3] = ["One Light", "Ayu Light", "Gruvbox Light"];
- const DARK_THEMES: [&'static str; 3] = ["One Dark", "Ayu Dark", "Gruvbox Dark"];
-
- let theme_names = match appearance {
- Appearance::Light => LIGHT_THEMES,
- Appearance::Dark => DARK_THEMES,
- };
- let themes = theme_names
- .map(|theme_name| theme_registry.get(theme_name))
- .map(Result::unwrap);
-
- let theme_previews = themes.map(|theme| {
- let is_selected = theme.name == current_theme_name;
- let name = theme.name.clone();
- let colors = cx.theme().colors();
-
- v_flex()
- .id(name.clone())
- .w_full()
- .items_center()
- .gap_1()
- .child(
- div()
- .w_full()
- .border_2()
- .border_color(colors.border_transparent)
- .rounded(ThemePreviewTile::CORNER_RADIUS)
- .map(|this| {
- if is_selected {
- this.border_color(colors.border_selected)
- } else {
- this.opacity(0.8).hover(|s| s.border_color(colors.border))
- }
- })
- .child(ThemePreviewTile::new(theme.clone(), theme_seed)),
- )
- .child(Label::new(name).color(Color::Muted).size(LabelSize::Small))
- .on_click({
- let theme_name = theme.name.clone();
- move |_, _, cx| {
- let fs = <dyn Fs>::global(cx);
- let theme_name = theme_name.clone();
- update_settings_file::<ThemeSettings>(fs, cx, move |settings, _| {
- settings.set_theme(theme_name, appearance);
- });
- }
- })
- });
+ let theme_mode = theme_selection
+ .mode()
+ .unwrap_or_else(|| match *system_appearance {
+ Appearance::Light => ThemeMode::Light,
+ Appearance::Dark => ThemeMode::Dark,
+ });
return v_flex()
.gap_2()
@@ -116,93 +41,148 @@ fn render_theme_section(window: &mut Window, cx: &mut App) -> impl IntoElement {
h_flex().justify_between().child(Label::new("Theme")).child(
ToggleButtonGroup::single_row(
"theme-selector-onboarding-dark-light",
- [
- ToggleButtonSimple::new("Light", {
- let appearance_state = appearance_state.clone();
- move |_, _, cx| {
- write_appearance_change(&appearance_state, Appearance::Light, cx);
- }
- }),
- ToggleButtonSimple::new("Dark", {
- let appearance_state = appearance_state.clone();
+ [ThemeMode::Light, ThemeMode::Dark, ThemeMode::System].map(|mode| {
+ const MODE_NAMES: [SharedString; 3] = [
+ SharedString::new_static("Light"),
+ SharedString::new_static("Dark"),
+ SharedString::new_static("System"),
+ ];
+ ToggleButtonSimple::new(
+ MODE_NAMES[mode as usize].clone(),
move |_, _, cx| {
- write_appearance_change(&appearance_state, Appearance::Dark, cx);
- }
- }),
- // TODO: Properly put the System back as a button within this group
- // Currently, given "System" is not an option in the Appearance enum,
- // this button doesn't get selected
- ToggleButtonSimple::new("System", {
- let theme = theme_selection.clone();
- move |_, _, cx| {
- toggle_system_theme_mode(theme.clone(), appearance, cx);
- }
- })
- .selected(theme_mode == ThemeMode::System),
- ],
+ write_mode_change(mode, cx);
+ },
+ )
+ }),
)
- .selected_index(selected_index)
+ .selected_index(theme_mode as usize)
.style(ui::ToggleButtonGroupStyle::Outlined)
.button_width(rems_from_px(64.)),
),
)
- .child(h_flex().gap_4().justify_between().children(theme_previews));
+ .child(
+ h_flex()
+ .gap_4()
+ .justify_between()
+ .children(render_theme_previews(&theme_selection, cx)),
+ );
- fn write_appearance_change(
- appearance_state: &Entity<Appearance>,
- new_appearance: Appearance,
+ fn render_theme_previews(
+ theme_selection: &ThemeSelection,
cx: &mut App,
- ) {
- let fs = <dyn Fs>::global(cx);
- appearance_state.write(cx, new_appearance);
+ ) -> [impl IntoElement; 3] {
+ let system_appearance = SystemAppearance::global(cx);
+ let theme_registry = ThemeRegistry::global(cx);
- update_settings_file::<ThemeSettings>(fs, cx, move |settings, _| {
- if settings.theme.as_ref().and_then(ThemeSelection::mode) == Some(ThemeMode::System) {
- return;
- }
- let new_mode = match new_appearance {
+ let theme_seed = 0xBEEF as f32;
+ let theme_mode = theme_selection
+ .mode()
+ .unwrap_or_else(|| match *system_appearance {
Appearance::Light => ThemeMode::Light,
Appearance::Dark => ThemeMode::Dark,
- };
- settings.set_mode(new_mode);
+ });
+ let appearance = match theme_mode {
+ ThemeMode::Light => Appearance::Light,
+ ThemeMode::Dark => Appearance::Dark,
+ ThemeMode::System => *system_appearance,
+ };
+ let current_theme_name = theme_selection.theme(appearance);
+
+ const LIGHT_THEMES: [&'static str; 3] = ["One Light", "Ayu Light", "Gruvbox Light"];
+ const DARK_THEMES: [&'static str; 3] = ["One Dark", "Ayu Dark", "Gruvbox Dark"];
+ const FAMILY_NAMES: [SharedString; 3] = [
+ SharedString::new_static("One"),
+ SharedString::new_static("Ayu"),
+ SharedString::new_static("Gruvbox"),
+ ];
+
+ let theme_names = match appearance {
+ Appearance::Light => LIGHT_THEMES,
+ Appearance::Dark => DARK_THEMES,
+ };
+
+ let themes = theme_names.map(|theme| theme_registry.get(theme).unwrap());
+
+ let theme_previews = [0, 1, 2].map(|index| {
+ let theme = &themes[index];
+ let is_selected = theme.name == current_theme_name;
+ let name = theme.name.clone();
+ let colors = cx.theme().colors();
+
+ v_flex()
+ .id(name.clone())
+ .w_full()
+ .items_center()
+ .gap_1()
+ .child(
+ h_flex()
+ .relative()
+ .w_full()
+ .border_2()
+ .border_color(colors.border_transparent)
+ .rounded(ThemePreviewTile::ROOT_RADIUS)
+ .map(|this| {
+ if is_selected {
+ this.border_color(colors.border_selected)
+ } else {
+ this.opacity(0.8).hover(|s| s.border_color(colors.border))
+ }
+ })
+ .map(|this| {
+ if theme_mode == ThemeMode::System {
+ let (light, dark) = (
+ theme_registry.get(LIGHT_THEMES[index]).unwrap(),
+ theme_registry.get(DARK_THEMES[index]).unwrap(),
+ );
+ this.child(
+ ThemePreviewTile::new(light, theme_seed)
+ .style(ThemePreviewStyle::SideBySide(dark)),
+ )
+ } else {
+ this.child(
+ ThemePreviewTile::new(theme.clone(), theme_seed)
+ .style(ThemePreviewStyle::Bordered),
+ )
+ }
+ }),
+ )
+ .child(
+ Label::new(FAMILY_NAMES[index].clone())
+ .color(Color::Muted)
+ .size(LabelSize::Small),
+ )
+ .on_click({
+ let theme_name = theme.name.clone();
+ move |_, _, cx| {
+ write_theme_change(theme_name.clone(), theme_mode, cx);
+ }
+ })
});
+
+ theme_previews
}
- fn toggle_system_theme_mode(
- theme_selection: ThemeSelection,
- appearance: Appearance,
- cx: &mut App,
- ) {
+ fn write_mode_change(mode: ThemeMode, cx: &mut App) {
let fs = <dyn Fs>::global(cx);
+ update_settings_file::<ThemeSettings>(fs, cx, move |settings, _cx| {
+ settings.set_mode(mode);
+ });
+ }
- update_settings_file::<ThemeSettings>(fs, cx, move |settings, _| {
- settings.theme = Some(match theme_selection {
- ThemeSelection::Static(theme_name) => ThemeSelection::Dynamic {
- mode: ThemeMode::System,
- light: theme_name.clone(),
- dark: theme_name.clone(),
- },
- ThemeSelection::Dynamic {
- mode: ThemeMode::System,
- light,
- dark,
- } => {
- let mode = match appearance {
- Appearance::Light => ThemeMode::Light,
- Appearance::Dark => ThemeMode::Dark,
- };
- ThemeSelection::Dynamic { mode, light, dark }
- }
- ThemeSelection::Dynamic {
- mode: _,
- light,
- dark,
- } => ThemeSelection::Dynamic {
+ fn write_theme_change(theme: impl Into<Arc<str>>, theme_mode: ThemeMode, cx: &mut App) {
+ let fs = <dyn Fs>::global(cx);
+ let theme = theme.into();
+ update_settings_file::<ThemeSettings>(fs, cx, move |settings, cx| {
+ if theme_mode == ThemeMode::System {
+ settings.theme = Some(ThemeSelection::Dynamic {
mode: ThemeMode::System,
- light,
- dark,
- },
- });
+ light: ThemeName(theme.clone()),
+ dark: ThemeName(theme.clone()),
+ });
+ } else {
+ let appearance = *SystemAppearance::global(cx);
+ settings.set_theme(theme.clone(), appearance);
+ }
});
}
}
@@ -1,175 +1,300 @@
#![allow(unused, dead_code)]
use gpui::{Hsla, Length};
use std::sync::Arc;
-use theme::{Theme, ThemeRegistry};
+use theme::{Theme, ThemeColors, ThemeRegistry};
use ui::{
IntoElement, RenderOnce, component_prelude::Documented, prelude::*, utils::inner_corner_radius,
};
+#[derive(Clone, PartialEq)]
+pub enum ThemePreviewStyle {
+ Bordered,
+ Borderless,
+ SideBySide(Arc<Theme>),
+}
+
/// Shows a preview of a theme as an abstract illustration
/// of a thumbnail-sized editor.
#[derive(IntoElement, RegisterComponent, Documented)]
pub struct ThemePreviewTile {
theme: Arc<Theme>,
seed: f32,
+ style: ThemePreviewStyle,
}
impl ThemePreviewTile {
- pub const CORNER_RADIUS: Pixels = px(8.0);
+ pub const SKELETON_HEIGHT_DEFAULT: Pixels = px(2.);
+ pub const SIDEBAR_SKELETON_ITEM_COUNT: usize = 8;
+ pub const SIDEBAR_WIDTH_DEFAULT: DefiniteLength = relative(0.25);
+ pub const ROOT_RADIUS: Pixels = px(8.0);
+ pub const ROOT_BORDER: Pixels = px(2.0);
+ pub const ROOT_PADDING: Pixels = px(2.0);
+ pub const CHILD_BORDER: Pixels = px(1.0);
+ pub const CHILD_RADIUS: std::cell::LazyCell<Pixels> = std::cell::LazyCell::new(|| {
+ inner_corner_radius(
+ Self::ROOT_RADIUS,
+ Self::ROOT_BORDER,
+ Self::ROOT_PADDING,
+ Self::CHILD_BORDER,
+ )
+ });
pub fn new(theme: Arc<Theme>, seed: f32) -> Self {
- Self { theme, seed }
+ Self {
+ theme,
+ seed,
+ style: ThemePreviewStyle::Bordered,
+ }
}
-}
-impl RenderOnce for ThemePreviewTile {
- fn render(self, _window: &mut ui::Window, _cx: &mut ui::App) -> impl IntoElement {
- let color = self.theme.colors();
+ pub fn style(mut self, style: ThemePreviewStyle) -> Self {
+ self.style = style;
+ self
+ }
- let root_radius = Self::CORNER_RADIUS;
- let root_border = px(2.0);
- let root_padding = px(2.0);
- let child_border = px(1.0);
- let inner_radius =
- inner_corner_radius(root_radius, root_border, root_padding, child_border);
+ pub fn item_skeleton(w: Length, h: Length, bg: Hsla) -> impl IntoElement {
+ div().w(w).h(h).rounded_full().bg(bg)
+ }
- let item_skeleton = |w: Length, h: Pixels, bg: Hsla| div().w(w).h(h).rounded_full().bg(bg);
+ pub fn render_sidebar_skeleton_items(
+ seed: f32,
+ colors: &ThemeColors,
+ skeleton_height: impl Into<Length> + Clone,
+ ) -> [impl IntoElement; Self::SIDEBAR_SKELETON_ITEM_COUNT] {
+ let skeleton_height = skeleton_height.into();
+ std::array::from_fn(|index| {
+ let width = {
+ let value = (seed * 1000.0 + index as f32 * 10.0).sin() * 0.5 + 0.5;
+ 0.5 + value * 0.45
+ };
+ Self::item_skeleton(
+ relative(width).into(),
+ skeleton_height,
+ colors.text.alpha(0.45),
+ )
+ })
+ }
- let skeleton_height = px(2.);
+ pub fn render_pseudo_code_skeleton(
+ seed: f32,
+ theme: Arc<Theme>,
+ skeleton_height: impl Into<Length>,
+ ) -> impl IntoElement {
+ let colors = theme.colors();
+ let syntax = theme.syntax();
- let sidebar_seeded_width = |seed: f32, index: usize| {
- let value = (seed * 1000.0 + index as f32 * 10.0).sin() * 0.5 + 0.5;
- 0.5 + value * 0.45
- };
+ let keyword_color = syntax.get("keyword").color;
+ let function_color = syntax.get("function").color;
+ let string_color = syntax.get("string").color;
+ let comment_color = syntax.get("comment").color;
+ let variable_color = syntax.get("variable").color;
+ let type_color = syntax.get("type").color;
+ let punctuation_color = syntax.get("punctuation").color;
- let sidebar_skeleton_items = 8;
+ let syntax_colors = [
+ keyword_color,
+ function_color,
+ string_color,
+ variable_color,
+ type_color,
+ punctuation_color,
+ comment_color,
+ ];
- let sidebar_skeleton = (0..sidebar_skeleton_items)
- .map(|i| {
- let width = sidebar_seeded_width(self.seed, i);
- item_skeleton(
- relative(width).into(),
- skeleton_height,
- color.text.alpha(0.45),
- )
- })
- .collect::<Vec<_>>();
+ let skeleton_height = skeleton_height.into();
- let sidebar = div()
- .h_full()
- .w(relative(0.25))
- .border_r(px(1.))
- .border_color(color.border_transparent)
- .bg(color.panel_background)
- .child(
- v_flex()
- .p_2()
- .size_full()
- .gap_1()
- .children(sidebar_skeleton),
- );
-
- let pseudo_code_skeleton = |theme: Arc<Theme>, seed: f32| -> AnyElement {
- let colors = theme.colors();
- let syntax = theme.syntax();
-
- let keyword_color = syntax.get("keyword").color;
- let function_color = syntax.get("function").color;
- let string_color = syntax.get("string").color;
- let comment_color = syntax.get("comment").color;
- let variable_color = syntax.get("variable").color;
- let type_color = syntax.get("type").color;
- let punctuation_color = syntax.get("punctuation").color;
-
- let syntax_colors = [
- keyword_color,
- function_color,
- string_color,
- variable_color,
- type_color,
- punctuation_color,
- comment_color,
- ];
-
- let line_width = |line_idx: usize, block_idx: usize| -> f32 {
- let val = (seed * 100.0 + line_idx as f32 * 20.0 + block_idx as f32 * 5.0).sin()
- * 0.5
- + 0.5;
- 0.05 + val * 0.2
- };
+ let line_width = |line_idx: usize, block_idx: usize| -> f32 {
+ let val =
+ (seed * 100.0 + line_idx as f32 * 20.0 + block_idx as f32 * 5.0).sin() * 0.5 + 0.5;
+ 0.05 + val * 0.2
+ };
- let indentation = |line_idx: usize| -> f32 {
- let step = line_idx % 6;
- if step < 3 {
- step as f32 * 0.1
- } else {
- (5 - step) as f32 * 0.1
- }
- };
+ let indentation = |line_idx: usize| -> f32 {
+ let step = line_idx % 6;
+ if step < 3 {
+ step as f32 * 0.1
+ } else {
+ (5 - step) as f32 * 0.1
+ }
+ };
- let pick_color = |line_idx: usize, block_idx: usize| -> Hsla {
- let idx = ((seed * 10.0 + line_idx as f32 * 7.0 + block_idx as f32 * 3.0).sin()
- * 3.5)
- .abs() as usize
- % syntax_colors.len();
- syntax_colors[idx].unwrap_or(colors.text)
- };
+ let pick_color = |line_idx: usize, block_idx: usize| -> Hsla {
+ let idx = ((seed * 10.0 + line_idx as f32 * 7.0 + block_idx as f32 * 3.0).sin() * 3.5)
+ .abs() as usize
+ % syntax_colors.len();
+ syntax_colors[idx].unwrap_or(colors.text)
+ };
- let line_count = 13;
+ let line_count = 13;
- let lines = (0..line_count)
- .map(|line_idx| {
- let block_count = (((seed * 30.0 + line_idx as f32 * 12.0).sin() * 0.5 + 0.5)
- * 3.0)
- .round() as usize
- + 2;
+ let lines = (0..line_count)
+ .map(|line_idx| {
+ let block_count = (((seed * 30.0 + line_idx as f32 * 12.0).sin() * 0.5 + 0.5) * 3.0)
+ .round() as usize
+ + 2;
- let indent = indentation(line_idx);
+ let indent = indentation(line_idx);
- let blocks = (0..block_count)
- .map(|block_idx| {
- let width = line_width(line_idx, block_idx);
- let color = pick_color(line_idx, block_idx);
- item_skeleton(relative(width).into(), skeleton_height, color)
- })
- .collect::<Vec<_>>();
+ let blocks = (0..block_count)
+ .map(|block_idx| {
+ let width = line_width(line_idx, block_idx);
+ let color = pick_color(line_idx, block_idx);
+ Self::item_skeleton(relative(width).into(), skeleton_height, color)
+ })
+ .collect::<Vec<_>>();
- h_flex().gap(px(2.)).ml(relative(indent)).children(blocks)
- })
- .collect::<Vec<_>>();
+ h_flex().gap(px(2.)).ml(relative(indent)).children(blocks)
+ })
+ .collect::<Vec<_>>();
- v_flex()
- .size_full()
- .p_1()
- .gap_1p5()
- .children(lines)
- .into_any_element()
- };
+ v_flex().size_full().p_1().gap_1p5().children(lines)
+ }
+
+ pub fn render_sidebar(
+ seed: f32,
+ colors: &ThemeColors,
+ width: impl Into<Length> + Clone,
+ skeleton_height: impl Into<Length>,
+ ) -> impl IntoElement {
+ div()
+ .h_full()
+ .w(width)
+ .border_r(px(1.))
+ .border_color(colors.border_transparent)
+ .bg(colors.panel_background)
+ .child(v_flex().p_2().size_full().gap_1().children(
+ Self::render_sidebar_skeleton_items(seed, colors, skeleton_height.into()),
+ ))
+ }
- let pane = v_flex().h_full().flex_grow().child(
+ pub fn render_pane(
+ seed: f32,
+ theme: Arc<Theme>,
+ skeleton_height: impl Into<Length>,
+ ) -> impl IntoElement {
+ v_flex().h_full().flex_grow().child(
div()
.size_full()
.overflow_hidden()
- .bg(color.editor_background)
+ .bg(theme.colors().editor_background)
.p_2()
- .child(pseudo_code_skeleton(self.theme.clone(), self.seed)),
- );
+ .child(Self::render_pseudo_code_skeleton(
+ seed,
+ theme,
+ skeleton_height.into(),
+ )),
+ )
+ }
- let content = div().size_full().flex().child(sidebar).child(pane);
+ pub fn render_editor(
+ seed: f32,
+ theme: Arc<Theme>,
+ sidebar_width: impl Into<Length> + Clone,
+ skeleton_height: impl Into<Length> + Clone,
+ ) -> impl IntoElement {
+ div()
+ .size_full()
+ .flex()
+ .bg(theme.colors().background.alpha(1.00))
+ .child(Self::render_sidebar(
+ seed,
+ theme.colors(),
+ sidebar_width,
+ skeleton_height.clone(),
+ ))
+ .child(Self::render_pane(seed, theme, skeleton_height.clone()))
+ }
+ fn render_borderless(seed: f32, theme: Arc<Theme>) -> impl IntoElement {
+ return Self::render_editor(
+ seed,
+ theme,
+ Self::SIDEBAR_WIDTH_DEFAULT,
+ Self::SKELETON_HEIGHT_DEFAULT,
+ );
+ }
+
+ fn render_border(seed: f32, theme: Arc<Theme>) -> impl IntoElement {
div()
.size_full()
- .rounded(root_radius)
- .p(root_padding)
+ .p(Self::ROOT_PADDING)
+ .rounded(Self::ROOT_RADIUS)
.child(
div()
.size_full()
- .rounded(inner_radius)
- .border(child_border)
- .border_color(color.border)
- .bg(color.background)
- .child(content),
+ .rounded(*Self::CHILD_RADIUS)
+ .border(Self::CHILD_BORDER)
+ .border_color(theme.colors().border)
+ .child(Self::render_editor(
+ seed,
+ theme.clone(),
+ Self::SIDEBAR_WIDTH_DEFAULT,
+ Self::SKELETON_HEIGHT_DEFAULT,
+ )),
+ )
+ }
+
+ fn render_side_by_side(
+ seed: f32,
+ theme: Arc<Theme>,
+ other_theme: Arc<Theme>,
+ border_color: Hsla,
+ ) -> impl IntoElement {
+ let sidebar_width = relative(0.20);
+
+ return div()
+ .size_full()
+ .p(Self::ROOT_PADDING)
+ .rounded(Self::ROOT_RADIUS)
+ .child(
+ h_flex()
+ .size_full()
+ .relative()
+ .rounded(*Self::CHILD_RADIUS)
+ .border(Self::CHILD_BORDER)
+ .border_color(border_color)
+ .overflow_hidden()
+ .child(div().size_full().child(Self::render_editor(
+ seed,
+ theme.clone(),
+ sidebar_width,
+ Self::SKELETON_HEIGHT_DEFAULT,
+ )))
+ .child(
+ div()
+ .size_full()
+ .absolute()
+ .left_1_2()
+ .bg(other_theme.colors().editor_background)
+ .child(Self::render_editor(
+ seed,
+ other_theme,
+ sidebar_width,
+ Self::SKELETON_HEIGHT_DEFAULT,
+ )),
+ ),
+ )
+ .into_any_element();
+ }
+}
+
+impl RenderOnce for ThemePreviewTile {
+ fn render(self, _window: &mut ui::Window, _cx: &mut ui::App) -> impl IntoElement {
+ match self.style {
+ ThemePreviewStyle::Bordered => {
+ Self::render_border(self.seed, self.theme).into_any_element()
+ }
+ ThemePreviewStyle::Borderless => {
+ Self::render_borderless(self.seed, self.theme).into_any_element()
+ }
+ ThemePreviewStyle::SideBySide(other_theme) => Self::render_side_by_side(
+ self.seed,
+ self.theme,
+ other_theme,
+ _cx.theme().colors().border,
)
+ .into_any_element(),
+ }
}
}