Add SVG preview (#32694)
Closes #10454 Implements SVG file preview capability similar to the existing markdown preview. - Adds `svg_preview` crate with preview view and live reloading upon file save. - Integrates SVG preview button in quick action bar. - File preview shortcuts (`ctrl/cmd+k v` and `ctrl/cmd+shift+v`) are extension-aware. Release Notes: - Added SVG file preview, accessible via the quick action bar button or keyboard shortcuts (`ctrl/cmd+k v` and `ctrl/cmd+shift+v`) when editing SVG files.
This commit is contained in:
parent
6c46e1129d
commit
e6bc1308af
16 changed files with 528 additions and 93 deletions
|
@ -85,6 +85,7 @@ libc.workspace = true
|
|||
log.workspace = true
|
||||
markdown.workspace = true
|
||||
markdown_preview.workspace = true
|
||||
svg_preview.workspace = true
|
||||
menu.workspace = true
|
||||
migrator.workspace = true
|
||||
mimalloc = { version = "0.1", optional = true }
|
||||
|
|
|
@ -582,6 +582,7 @@ pub fn main() {
|
|||
jj_ui::init(cx);
|
||||
feedback::init(cx);
|
||||
markdown_preview::init(cx);
|
||||
svg_preview::init(cx);
|
||||
welcome::init(cx);
|
||||
settings_ui::init(cx);
|
||||
extensions_ui::init(cx);
|
||||
|
|
|
@ -4323,6 +4323,7 @@ mod tests {
|
|||
"search",
|
||||
"snippets",
|
||||
"supermaven",
|
||||
"svg",
|
||||
"tab_switcher",
|
||||
"task",
|
||||
"terminal",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod markdown_preview;
|
||||
mod preview;
|
||||
mod repl_menu;
|
||||
|
||||
use agent_settings::AgentSettings;
|
||||
use editor::actions::{
|
||||
AddSelectionAbove, AddSelectionBelow, CodeActionSource, DuplicateLineDown, GoToDiagnostic,
|
||||
|
@ -571,7 +572,7 @@ impl Render for QuickActionBar {
|
|||
.id("quick action bar")
|
||||
.gap(DynamicSpacing::Base01.rems(cx))
|
||||
.children(self.render_repl_menu(cx))
|
||||
.children(self.render_toggle_markdown_preview(self.workspace.clone(), cx))
|
||||
.children(self.render_preview_button(self.workspace.clone(), cx))
|
||||
.children(search_button)
|
||||
.when(
|
||||
AgentSettings::get_global(cx).enabled && AgentSettings::get_global(cx).button,
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
use gpui::{AnyElement, Modifiers, WeakEntity};
|
||||
use markdown_preview::{
|
||||
OpenPreview, OpenPreviewToTheSide, markdown_preview_view::MarkdownPreviewView,
|
||||
};
|
||||
use ui::{IconButtonShape, Tooltip, prelude::*, text_for_keystroke};
|
||||
use workspace::Workspace;
|
||||
|
||||
use super::QuickActionBar;
|
||||
|
||||
impl QuickActionBar {
|
||||
pub fn render_toggle_markdown_preview(
|
||||
&self,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<AnyElement> {
|
||||
let mut active_editor_is_markdown = false;
|
||||
|
||||
if let Some(workspace) = self.workspace.upgrade() {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
active_editor_is_markdown =
|
||||
MarkdownPreviewView::resolve_active_item_as_markdown_editor(workspace, cx)
|
||||
.is_some();
|
||||
});
|
||||
}
|
||||
|
||||
if !active_editor_is_markdown {
|
||||
return None;
|
||||
}
|
||||
|
||||
let alt_click = gpui::Keystroke {
|
||||
key: "click".into(),
|
||||
modifiers: Modifiers::alt(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let button = IconButton::new("toggle-markdown-preview", IconName::Eye)
|
||||
.shape(IconButtonShape::Square)
|
||||
.icon_size(IconSize::Small)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.tooltip(move |window, cx| {
|
||||
Tooltip::with_meta(
|
||||
"Preview Markdown",
|
||||
Some(&markdown_preview::OpenPreview),
|
||||
format!("{} to open in a split", text_for_keystroke(&alt_click, cx)),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.on_click(move |_, window, cx| {
|
||||
if let Some(workspace) = workspace.upgrade() {
|
||||
workspace.update(cx, |_, cx| {
|
||||
if window.modifiers().alt {
|
||||
window.dispatch_action(Box::new(OpenPreviewToTheSide), cx);
|
||||
} else {
|
||||
window.dispatch_action(Box::new(OpenPreview), cx);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Some(button.into_any_element())
|
||||
}
|
||||
}
|
95
crates/zed/src/zed/quick_action_bar/preview.rs
Normal file
95
crates/zed/src/zed/quick_action_bar/preview.rs
Normal file
|
@ -0,0 +1,95 @@
|
|||
use gpui::{AnyElement, Modifiers, WeakEntity};
|
||||
use markdown_preview::{
|
||||
OpenPreview as MarkdownOpenPreview, OpenPreviewToTheSide as MarkdownOpenPreviewToTheSide,
|
||||
markdown_preview_view::MarkdownPreviewView,
|
||||
};
|
||||
use svg_preview::{
|
||||
OpenPreview as SvgOpenPreview, OpenPreviewToTheSide as SvgOpenPreviewToTheSide,
|
||||
svg_preview_view::SvgPreviewView,
|
||||
};
|
||||
use ui::{IconButtonShape, Tooltip, prelude::*, text_for_keystroke};
|
||||
use workspace::Workspace;
|
||||
|
||||
use super::QuickActionBar;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum PreviewType {
|
||||
Markdown,
|
||||
Svg,
|
||||
}
|
||||
|
||||
impl QuickActionBar {
|
||||
pub fn render_preview_button(
|
||||
&self,
|
||||
workspace_handle: WeakEntity<Workspace>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<AnyElement> {
|
||||
let mut preview_type = None;
|
||||
|
||||
if let Some(workspace) = self.workspace.upgrade() {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
if MarkdownPreviewView::resolve_active_item_as_markdown_editor(workspace, cx)
|
||||
.is_some()
|
||||
{
|
||||
preview_type = Some(PreviewType::Markdown);
|
||||
} else if SvgPreviewView::resolve_active_item_as_svg_editor(workspace, cx).is_some()
|
||||
{
|
||||
preview_type = Some(PreviewType::Svg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let preview_type = preview_type?;
|
||||
|
||||
let (button_id, tooltip_text, open_action, open_to_side_action, open_action_for_tooltip) =
|
||||
match preview_type {
|
||||
PreviewType::Markdown => (
|
||||
"toggle-markdown-preview",
|
||||
"Preview Markdown",
|
||||
Box::new(MarkdownOpenPreview) as Box<dyn gpui::Action>,
|
||||
Box::new(MarkdownOpenPreviewToTheSide) as Box<dyn gpui::Action>,
|
||||
&markdown_preview::OpenPreview as &dyn gpui::Action,
|
||||
),
|
||||
PreviewType::Svg => (
|
||||
"toggle-svg-preview",
|
||||
"Preview SVG",
|
||||
Box::new(SvgOpenPreview) as Box<dyn gpui::Action>,
|
||||
Box::new(SvgOpenPreviewToTheSide) as Box<dyn gpui::Action>,
|
||||
&svg_preview::OpenPreview as &dyn gpui::Action,
|
||||
),
|
||||
};
|
||||
|
||||
let alt_click = gpui::Keystroke {
|
||||
key: "click".into(),
|
||||
modifiers: Modifiers::alt(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let button = IconButton::new(button_id, IconName::Eye)
|
||||
.shape(IconButtonShape::Square)
|
||||
.icon_size(IconSize::Small)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.tooltip(move |window, cx| {
|
||||
Tooltip::with_meta(
|
||||
tooltip_text,
|
||||
Some(open_action_for_tooltip),
|
||||
format!("{} to open in a split", text_for_keystroke(&alt_click, cx)),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.on_click(move |_, window, cx| {
|
||||
if let Some(workspace) = workspace_handle.upgrade() {
|
||||
workspace.update(cx, |_, cx| {
|
||||
if window.modifiers().alt {
|
||||
window.dispatch_action(open_to_side_action.boxed_clone(), cx);
|
||||
} else {
|
||||
window.dispatch_action(open_action.boxed_clone(), cx);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Some(button.into_any_element())
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue