crates/extensions_ui/src/components.rs ๐
@@ -1,5 +1,3 @@
mod extension_card;
-mod feature_upsell;
pub use extension_card::*;
-pub use feature_upsell::*;
Danilo Leal created
Closes https://github.com/zed-industries/zed/issues/41168
This PR adds both Tailwind CSS and Ruff (linter for Python) as built-in
features; a banner mentioning this should show up now for these two when
searching for them in the extensions UI.
There will also be a corresponding zed.dev site PR adding a "Ruff is
built-in" card to the zed.dev/extensions page.
Release Notes:
- N/A
crates/extensions_ui/src/components.rs | 2
crates/extensions_ui/src/components/feature_upsell.rs | 77 ----
crates/extensions_ui/src/extensions_ui.rs | 246 +++++++++---
3 files changed, 182 insertions(+), 143 deletions(-)
@@ -1,5 +1,3 @@
mod extension_card;
-mod feature_upsell;
pub use extension_card::*;
-pub use feature_upsell::*;
@@ -1,77 +0,0 @@
-use gpui::{AnyElement, Div, StyleRefinement};
-use smallvec::SmallVec;
-use ui::prelude::*;
-
-#[derive(IntoElement)]
-pub struct FeatureUpsell {
- base: Div,
- text: SharedString,
- docs_url: Option<SharedString>,
- children: SmallVec<[AnyElement; 2]>,
-}
-
-impl FeatureUpsell {
- pub fn new(text: impl Into<SharedString>) -> Self {
- Self {
- base: h_flex(),
- text: text.into(),
- docs_url: None,
- children: SmallVec::new(),
- }
- }
-
- pub fn docs_url(mut self, docs_url: impl Into<SharedString>) -> Self {
- self.docs_url = Some(docs_url.into());
- self
- }
-}
-
-impl ParentElement for FeatureUpsell {
- fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
- self.children.extend(elements)
- }
-}
-
-// Style methods.
-impl FeatureUpsell {
- fn style(&mut self) -> &mut StyleRefinement {
- self.base.style()
- }
-
- gpui::border_style_methods!({
- visibility: pub
- });
-}
-
-impl RenderOnce for FeatureUpsell {
- fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
- self.base
- .py_2()
- .px_4()
- .justify_between()
- .flex_wrap()
- .border_color(cx.theme().colors().border_variant)
- .child(Label::new(self.text))
- .child(h_flex().gap_2().children(self.children).when_some(
- self.docs_url,
- |el, docs_url| {
- el.child(
- Button::new("open_docs", "View Documentation")
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::End)
- .on_click({
- move |_event, _window, cx| {
- telemetry::event!(
- "Documentation Viewed",
- source = "Feature Upsell",
- url = docs_url,
- );
- cx.open_url(&docs_url)
- }
- }),
- )
- },
- ))
- }
-}
@@ -24,8 +24,8 @@ use settings::{Settings, SettingsContent};
use strum::IntoEnumIterator as _;
use theme::ThemeSettings;
use ui::{
- CheckboxWithLabel, Chip, ContextMenu, PopoverMenu, ScrollableHandle, ToggleButton, Tooltip,
- WithScrollbar, prelude::*,
+ Banner, Chip, ContextMenu, Divider, PopoverMenu, ScrollableHandle, Switch, ToggleButton,
+ Tooltip, WithScrollbar, prelude::*,
};
use vim_mode_setting::VimModeSetting;
use workspace::{
@@ -34,7 +34,7 @@ use workspace::{
};
use zed_actions::ExtensionCategoryFilter;
-use crate::components::{ExtensionCard, FeatureUpsell};
+use crate::components::ExtensionCard;
use crate::extension_version_selector::{
ExtensionVersionSelector, ExtensionVersionSelectorDelegate,
};
@@ -225,9 +225,9 @@ impl ExtensionFilter {
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
enum Feature {
+ ExtensionRuff,
+ ExtensionTailwind,
Git,
- OpenIn,
- Vim,
LanguageBash,
LanguageC,
LanguageCpp,
@@ -236,13 +236,28 @@ enum Feature {
LanguageReact,
LanguageRust,
LanguageTypescript,
+ OpenIn,
+ Vim,
}
fn keywords_by_feature() -> &'static BTreeMap<Feature, Vec<&'static str>> {
static KEYWORDS_BY_FEATURE: OnceLock<BTreeMap<Feature, Vec<&'static str>>> = OnceLock::new();
KEYWORDS_BY_FEATURE.get_or_init(|| {
BTreeMap::from_iter([
+ (Feature::ExtensionRuff, vec!["ruff"]),
+ (Feature::ExtensionTailwind, vec!["tail", "tailwind"]),
(Feature::Git, vec!["git"]),
+ (Feature::LanguageBash, vec!["sh", "bash"]),
+ (Feature::LanguageC, vec!["c", "clang"]),
+ (Feature::LanguageCpp, vec!["c++", "cpp", "clang"]),
+ (Feature::LanguageGo, vec!["go", "golang"]),
+ (Feature::LanguagePython, vec!["python", "py"]),
+ (Feature::LanguageReact, vec!["react"]),
+ (Feature::LanguageRust, vec!["rust", "rs"]),
+ (
+ Feature::LanguageTypescript,
+ vec!["type", "typescript", "ts"],
+ ),
(
Feature::OpenIn,
vec![
@@ -257,17 +272,6 @@ fn keywords_by_feature() -> &'static BTreeMap<Feature, Vec<&'static str>> {
],
),
(Feature::Vim, vec!["vim"]),
- (Feature::LanguageBash, vec!["sh", "bash"]),
- (Feature::LanguageC, vec!["c", "clang"]),
- (Feature::LanguageCpp, vec!["c++", "cpp", "clang"]),
- (Feature::LanguageGo, vec!["go", "golang"]),
- (Feature::LanguagePython, vec!["python", "py"]),
- (Feature::LanguageReact, vec!["react"]),
- (Feature::LanguageRust, vec!["rust", "rs"]),
- (
- Feature::LanguageTypescript,
- vec!["type", "typescript", "ts"],
- ),
])
})
}
@@ -1336,58 +1340,172 @@ impl ExtensionsPage {
}
}
- fn render_feature_upsells(&self, cx: &mut Context<Self>) -> impl IntoElement {
- let upsells_count = self.upsells.len();
+ fn render_feature_upsell_banner(
+ &self,
+ label: SharedString,
+ docs_url: SharedString,
+ vim: bool,
+ cx: &mut Context<Self>,
+ ) -> impl IntoElement {
+ let docs_url_button = Button::new("open_docs", "View Documentation")
+ .icon(IconName::ArrowUpRight)
+ .icon_size(IconSize::Small)
+ .icon_position(IconPosition::End)
+ .on_click({
+ move |_event, _window, cx| {
+ telemetry::event!(
+ "Documentation Viewed",
+ source = "Feature Upsell",
+ url = docs_url,
+ );
+ cx.open_url(&docs_url)
+ }
+ });
- v_flex().children(self.upsells.iter().enumerate().map(|(ix, feature)| {
- let upsell = match feature {
- Feature::Git => FeatureUpsell::new(
- "Zed comes with basic Git support. More Git features are coming in the future.",
- )
- .docs_url("https://zed.dev/docs/git"),
- Feature::OpenIn => FeatureUpsell::new(
- "Zed supports linking to a source line on GitHub and others.",
- )
- .docs_url("https://zed.dev/docs/git#git-integrations"),
- Feature::Vim => FeatureUpsell::new("Vim support is built-in to Zed!")
- .docs_url("https://zed.dev/docs/vim")
- .child(CheckboxWithLabel::new(
- "enable-vim",
- Label::new("Enable vim mode"),
- if VimModeSetting::get_global(cx).0 {
- ui::ToggleState::Selected
+ div()
+ .pt_4()
+ .px_4()
+ .child(
+ Banner::new()
+ .severity(Severity::Success)
+ .child(Label::new(label).mt_0p5())
+ .map(|this| {
+ if vim {
+ this.action_slot(
+ h_flex()
+ .gap_1()
+ .child(docs_url_button)
+ .child(Divider::vertical().color(ui::DividerColor::Border))
+ .child(
+ h_flex()
+ .pl_1()
+ .gap_1()
+ .child(Label::new("Enable Vim mode"))
+ .child(
+ Switch::new(
+ "enable-vim",
+ if VimModeSetting::get_global(cx).0 {
+ ui::ToggleState::Selected
+ } else {
+ ui::ToggleState::Unselected
+ },
+ )
+ .on_click(cx.listener(
+ move |this, selection, _, cx| {
+ telemetry::event!(
+ "Vim Mode Toggled",
+ source = "Feature Upsell"
+ );
+ this.update_settings(
+ selection,
+ cx,
+ |setting, value| {
+ setting.vim_mode = Some(value)
+ },
+ );
+ },
+ ))
+ .color(ui::SwitchColor::Accent),
+ ),
+ ),
+ )
} else {
- ui::ToggleState::Unselected
- },
- cx.listener(move |this, selection, _, cx| {
- telemetry::event!("Vim Mode Toggled", source = "Feature Upsell");
- this.update_settings(selection, cx, |setting, value| {
- setting.vim_mode = Some(value)
- });
- }),
- )),
- Feature::LanguageBash => FeatureUpsell::new("Shell support is built-in to Zed!")
- .docs_url("https://zed.dev/docs/languages/bash"),
- Feature::LanguageC => FeatureUpsell::new("C support is built-in to Zed!")
- .docs_url("https://zed.dev/docs/languages/c"),
- Feature::LanguageCpp => FeatureUpsell::new("C++ support is built-in to Zed!")
- .docs_url("https://zed.dev/docs/languages/cpp"),
- Feature::LanguageGo => FeatureUpsell::new("Go support is built-in to Zed!")
- .docs_url("https://zed.dev/docs/languages/go"),
- Feature::LanguagePython => FeatureUpsell::new("Python support is built-in to Zed!")
- .docs_url("https://zed.dev/docs/languages/python"),
- Feature::LanguageReact => FeatureUpsell::new("React support is built-in to Zed!")
- .docs_url("https://zed.dev/docs/languages/typescript"),
- Feature::LanguageRust => FeatureUpsell::new("Rust support is built-in to Zed!")
- .docs_url("https://zed.dev/docs/languages/rust"),
- Feature::LanguageTypescript => {
- FeatureUpsell::new("Typescript support is built-in to Zed!")
- .docs_url("https://zed.dev/docs/languages/typescript")
- }
+ this.action_slot(docs_url_button)
+ }
+ }),
+ )
+ .into_any_element()
+ }
+
+ fn render_feature_upsells(&self, cx: &mut Context<Self>) -> impl IntoElement {
+ let mut container = v_flex();
+
+ for feature in &self.upsells {
+ let banner = match feature {
+ Feature::ExtensionRuff => self.render_feature_upsell_banner(
+ "Ruff (linter for Python) support is built-in to Zed!".into(),
+ "https://zed.dev/docs/languages/python#code-formatting--linting".into(),
+ false,
+ cx,
+ ),
+ Feature::ExtensionTailwind => self.render_feature_upsell_banner(
+ "Tailwind CSS support is built-in to Zed!".into(),
+ "https://zed.dev/docs/languages/tailwindcss".into(),
+ false,
+ cx,
+ ),
+ Feature::Git => self.render_feature_upsell_banner(
+ "Zed comes with basic Git supportโmore features are coming in the future."
+ .into(),
+ "https://zed.dev/docs/git".into(),
+ false,
+ cx,
+ ),
+ Feature::LanguageBash => self.render_feature_upsell_banner(
+ "Shell support is built-in to Zed!".into(),
+ "https://zed.dev/docs/languages/bash".into(),
+ false,
+ cx,
+ ),
+ Feature::LanguageC => self.render_feature_upsell_banner(
+ "C support is built-in to Zed!".into(),
+ "https://zed.dev/docs/languages/c".into(),
+ false,
+ cx,
+ ),
+ Feature::LanguageCpp => self.render_feature_upsell_banner(
+ "C++ support is built-in to Zed!".into(),
+ "https://zed.dev/docs/languages/cpp".into(),
+ false,
+ cx,
+ ),
+ Feature::LanguageGo => self.render_feature_upsell_banner(
+ "Go support is built-in to Zed!".into(),
+ "https://zed.dev/docs/languages/go".into(),
+ false,
+ cx,
+ ),
+ Feature::LanguagePython => self.render_feature_upsell_banner(
+ "Python support is built-in to Zed!".into(),
+ "https://zed.dev/docs/languages/python".into(),
+ false,
+ cx,
+ ),
+ Feature::LanguageReact => self.render_feature_upsell_banner(
+ "React support is built-in to Zed!".into(),
+ "https://zed.dev/docs/languages/typescript".into(),
+ false,
+ cx,
+ ),
+ Feature::LanguageRust => self.render_feature_upsell_banner(
+ "Rust support is built-in to Zed!".into(),
+ "https://zed.dev/docs/languages/rust".into(),
+ false,
+ cx,
+ ),
+ Feature::LanguageTypescript => self.render_feature_upsell_banner(
+ "Typescript support is built-in to Zed!".into(),
+ "https://zed.dev/docs/languages/typescript".into(),
+ false,
+ cx,
+ ),
+ Feature::OpenIn => self.render_feature_upsell_banner(
+ "Zed supports linking to a source line on GitHub and others.".into(),
+ "https://zed.dev/docs/git#git-integrations".into(),
+ false,
+ cx,
+ ),
+ Feature::Vim => self.render_feature_upsell_banner(
+ "Vim support is built-in to Zed!".into(),
+ "https://zed.dev/docs/vim".into(),
+ true,
+ cx,
+ ),
};
+ container = container.child(banner);
+ }
- upsell.when(ix < upsells_count, |upsell| upsell.border_b_1())
- }))
+ container
}
}