Merge pull request #2146 from zed-industries/feedback-editor-polish

Feedback editor polish
This commit is contained in:
Joseph T. Lyons 2023-02-09 10:01:27 -05:00 committed by Joseph Lyons
parent 4841d85da7
commit 7d3fe56723
6 changed files with 144 additions and 6 deletions

View file

@ -31,7 +31,6 @@ use workspace::{
use crate::system_specs::SystemSpecs; use crate::system_specs::SystemSpecs;
const FEEDBACK_CHAR_LIMIT: RangeInclusive<usize> = 10..=5000; const FEEDBACK_CHAR_LIMIT: RangeInclusive<usize> = 10..=5000;
const FEEDBACK_PLACEHOLDER_TEXT: &str = "Save to submit feedback as Markdown.";
const FEEDBACK_SUBMISSION_ERROR_TEXT: &str = const FEEDBACK_SUBMISSION_ERROR_TEXT: &str =
"Feedback failed to submit, see error log for details."; "Feedback failed to submit, see error log for details.";
@ -117,7 +116,6 @@ impl FeedbackEditor {
let editor = cx.add_view(|cx| { let editor = cx.add_view(|cx| {
let mut editor = Editor::for_buffer(buffer, Some(project.clone()), cx); let mut editor = Editor::for_buffer(buffer, Some(project.clone()), cx);
editor.set_vertical_scroll_margin(5, cx); editor.set_vertical_scroll_margin(5, cx);
editor.set_placeholder_text(FEEDBACK_PLACEHOLDER_TEXT, cx);
editor editor
}); });
@ -483,6 +481,13 @@ impl View for SubmitFeedbackButton {
.aligned() .aligned()
.contained() .contained()
.with_margin_left(theme.feedback.button_margin) .with_margin_left(theme.feedback.button_margin)
.with_tooltip::<Self, _>(
0,
"cmd-s".into(),
Some(Box::new(SubmitFeedback)),
theme.tooltip.clone(),
cx,
)
.boxed() .boxed()
} }
} }
@ -504,3 +509,56 @@ impl ToolbarItemView for SubmitFeedbackButton {
} }
} }
} }
pub struct FeedbackInfoText {
active_item: Option<ViewHandle<FeedbackEditor>>,
}
impl FeedbackInfoText {
pub fn new() -> Self {
Self {
active_item: Default::default(),
}
}
}
impl Entity for FeedbackInfoText {
type Event = ();
}
impl View for FeedbackInfoText {
fn ui_name() -> &'static str {
"FeedbackInfoText"
}
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
let theme = cx.global::<Settings>().theme.clone();
let text = "We read whatever you submit here. For issues and discussions, visit the community repo on GitHub.";
Label::new(text.to_string(), theme.feedback.info_text.text.clone())
.contained()
.aligned()
.left()
.clipped()
.boxed()
}
}
impl ToolbarItemView for FeedbackInfoText {
fn set_active_pane_item(
&mut self,
active_pane_item: Option<&dyn ItemHandle>,
cx: &mut ViewContext<Self>,
) -> workspace::ToolbarItemLocation {
cx.notify();
if let Some(feedback_editor) = active_pane_item.and_then(|i| i.downcast::<FeedbackEditor>())
{
self.active_item = Some(feedback_editor);
ToolbarItemLocation::PrimaryLeft {
flex: Some((1., false)),
}
} else {
self.active_item = None;
ToolbarItemLocation::Hidden
}
}
}

View file

@ -1,5 +1,6 @@
mod align; mod align;
mod canvas; mod canvas;
mod clipped;
mod constrained_box; mod constrained_box;
mod container; mod container;
mod empty; mod empty;
@ -19,12 +20,12 @@ mod text;
mod tooltip; mod tooltip;
mod uniform_list; mod uniform_list;
use self::expanded::Expanded;
pub use self::{ pub use self::{
align::*, canvas::*, constrained_box::*, container::*, empty::*, flex::*, hook::*, image::*, align::*, canvas::*, constrained_box::*, container::*, empty::*, flex::*, hook::*, image::*,
keystroke_label::*, label::*, list::*, mouse_event_handler::*, overlay::*, resizable::*, keystroke_label::*, label::*, list::*, mouse_event_handler::*, overlay::*, resizable::*,
stack::*, svg::*, text::*, tooltip::*, uniform_list::*, stack::*, svg::*, text::*, tooltip::*, uniform_list::*,
}; };
use self::{clipped::Clipped, expanded::Expanded};
pub use crate::presenter::ChildView; pub use crate::presenter::ChildView;
use crate::{ use crate::{
geometry::{ geometry::{
@ -135,6 +136,13 @@ pub trait Element {
Align::new(self.boxed()) Align::new(self.boxed())
} }
fn clipped(self) -> Clipped
where
Self: 'static + Sized,
{
Clipped::new(self.boxed())
}
fn contained(self) -> Container fn contained(self) -> Container
where where
Self: 'static + Sized, Self: 'static + Sized,

View file

@ -0,0 +1,69 @@
use std::ops::Range;
use pathfinder_geometry::{rect::RectF, vector::Vector2F};
use serde_json::json;
use crate::{
json, DebugContext, Element, ElementBox, LayoutContext, MeasurementContext, PaintContext,
SizeConstraint,
};
pub struct Clipped {
child: ElementBox,
}
impl Clipped {
pub fn new(child: ElementBox) -> Self {
Self { child }
}
}
impl Element for Clipped {
type LayoutState = ();
type PaintState = ();
fn layout(
&mut self,
constraint: SizeConstraint,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
(self.child.layout(constraint, cx), ())
}
fn paint(
&mut self,
bounds: RectF,
visible_bounds: RectF,
_: &mut Self::LayoutState,
cx: &mut PaintContext,
) -> Self::PaintState {
cx.scene.push_layer(Some(bounds));
self.child.paint(bounds.origin(), visible_bounds, cx);
cx.scene.pop_layer();
}
fn rect_for_text_range(
&self,
range_utf16: Range<usize>,
_: RectF,
_: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
cx: &MeasurementContext,
) -> Option<RectF> {
self.child.rect_for_text_range(range_utf16, cx)
}
fn debug(
&self,
_: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
cx: &DebugContext,
) -> json::Value {
json!({
"type": "Clipped",
"child": self.child.debug(cx)
})
}
}

View file

@ -811,6 +811,7 @@ pub struct TerminalStyle {
pub struct FeedbackStyle { pub struct FeedbackStyle {
pub submit_button: Interactive<ContainedText>, pub submit_button: Interactive<ContainedText>,
pub button_margin: f32, pub button_margin: f32,
pub info_text: ContainedText,
} }
#[derive(Clone, Deserialize, Default)] #[derive(Clone, Deserialize, Default)]

View file

@ -11,7 +11,7 @@ use collections::VecDeque;
pub use editor; pub use editor;
use editor::{Editor, MultiBuffer}; use editor::{Editor, MultiBuffer};
use feedback::feedback_editor::SubmitFeedbackButton; use feedback::feedback_editor::{FeedbackInfoText, SubmitFeedbackButton};
use futures::StreamExt; use futures::StreamExt;
use gpui::{ use gpui::{
actions, actions,
@ -290,6 +290,8 @@ pub fn initialize_workspace(
toolbar.add_item(project_search_bar, cx); toolbar.add_item(project_search_bar, cx);
let submit_feedback_button = cx.add_view(|_| SubmitFeedbackButton::new()); let submit_feedback_button = cx.add_view(|_| SubmitFeedbackButton::new());
toolbar.add_item(submit_feedback_button, cx); toolbar.add_item(submit_feedback_button, cx);
let feedback_info_text = cx.add_view(|_| FeedbackInfoText::new());
toolbar.add_item(feedback_info_text, cx);
}) })
}); });
} }

View file

@ -5,7 +5,6 @@ import { background, border, text } from "./components";
export default function feedback(colorScheme: ColorScheme) { export default function feedback(colorScheme: ColorScheme) {
let layer = colorScheme.highest; let layer = colorScheme.highest;
// Currently feedback only needs style for the submit feedback button
return { return {
submit_button: { submit_button: {
...text(layer, "mono", "on"), ...text(layer, "mono", "on"),
@ -32,6 +31,7 @@ export default function feedback(colorScheme: ColorScheme) {
border: border(layer, "on", "hovered"), border: border(layer, "on", "hovered"),
}, },
}, },
button_margin: 8 button_margin: 8,
info_text: text(layer, "sans", "default", { size: "xs" }),
}; };
} }