Detailed changes
@@ -15,7 +15,7 @@ use markdown::{Markdown, MarkdownElement};
use project::{git_store::Repository, project_settings::ProjectSettings};
use settings::Settings as _;
use theme::ThemeSettings;
-use time::OffsetDateTime;
+use time::{OffsetDateTime, ext::NumericalDuration};
use time_format::format_local_timestamp;
use ui::{ContextMenu, Divider, IconButtonShape, prelude::*, tooltip_container};
use workspace::Workspace;
@@ -42,7 +42,7 @@ impl BlameRenderer for GitBlameRenderer {
window: &mut Window,
cx: &mut App,
) -> Option<AnyElement> {
- let relative_timestamp = blame_entry_relative_timestamp(&blame_entry);
+ let (time_color, relative_timestamp) = blame_entry_relative_timestamp(cx, &blame_entry);
let short_commit_id = blame_entry.sha.display_short();
let author_name = blame_entry.author.as_deref().unwrap_or("<no name>");
let name = util::truncate_and_trailoff(author_name, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED);
@@ -80,7 +80,7 @@ impl BlameRenderer for GitBlameRenderer {
.children(avatar)
.child(name),
)
- .child(relative_timestamp)
+ .child(div().text_color(time_color).child(relative_timestamp))
.hover(|style| style.bg(cx.theme().colors().element_hover))
.cursor_pointer()
.on_mouse_down(MouseButton::Right, {
@@ -150,7 +150,7 @@ impl BlameRenderer for GitBlameRenderer {
blame_entry: BlameEntry,
cx: &mut App,
) -> Option<AnyElement> {
- let relative_timestamp = blame_entry_relative_timestamp(&blame_entry);
+ let (_, relative_timestamp) = blame_entry_relative_timestamp(cx, &blame_entry);
let author = blame_entry.author.as_deref().unwrap_or_default();
let summary_enabled = ProjectSettings::get_global(cx)
.git
@@ -415,17 +415,32 @@ fn deploy_blame_entry_context_menu(
});
}
-fn blame_entry_relative_timestamp(blame_entry: &BlameEntry) -> String {
+fn blame_entry_relative_timestamp(cx: &App, blame_entry: &BlameEntry) -> (Hsla, String) {
match blame_entry.author_offset_date_time() {
Ok(timestamp) => {
+ let mut color = cx.theme().colors().version_control_blame_age_new;
let local = chrono::Local::now().offset().local_minus_utc();
- time_format::format_localized_timestamp(
- timestamp,
- time::OffsetDateTime::now_utc(),
- time::UtcOffset::from_whole_seconds(local).unwrap(),
- time_format::TimestampFormat::Relative,
+ let now = time::OffsetDateTime::now_utc();
+
+ // Gradient over ~2 years
+ let recency = ((now - timestamp - 2.hours()).as_seconds_f32()
+ / 106.weeks().as_seconds_f32())
+ .clamp(0.0, 1.0);
+ // Sqrt to make more recent colors change more strongly
+ color.l *= 1. - 0.45 * recency.sqrt();
+ (
+ color,
+ time_format::format_localized_timestamp(
+ timestamp,
+ now,
+ time::UtcOffset::from_whole_seconds(local).unwrap(),
+ time_format::TimestampFormat::Relative,
+ ),
)
}
- Err(_) => "Error parsing date".to_string(),
+ Err(_) => (
+ cx.theme().colors().terminal_ansi_bright_red,
+ "Error parsing date".to_string(),
+ ),
}
}
@@ -777,6 +777,14 @@ pub struct ThemeColorsContent {
/// Deprecated in favor of `version_control_conflict_marker_theirs`.
#[deprecated]
pub version_control_conflict_theirs_background: Option<String>,
+
+ /// Blame gutter color for new revisions.
+ #[serde(rename = "version_control.blame.age_new")]
+ pub version_control_blame_age_new: Option<String>,
+
+ /// Blame gutter color for old revisions.
+ #[serde(rename = "version_control.blame.age_old")]
+ pub version_control_blame_age_old: Option<String>,
}
#[skip_serializing_none]
@@ -154,6 +154,8 @@ impl ThemeColors {
version_control_ignored: gray().light().step_12(),
version_control_conflict_marker_ours: green().light().step_10().alpha(0.5),
version_control_conflict_marker_theirs: blue().light().step_10().alpha(0.5),
+ version_control_blame_age_new: orange().light().step_10(),
+ version_control_blame_age_old: blue().light().step_10(),
}
}
@@ -280,6 +282,8 @@ impl ThemeColors {
version_control_ignored: gray().dark().step_12(),
version_control_conflict_marker_ours: green().dark().step_10().alpha(0.5),
version_control_conflict_marker_theirs: blue().dark().step_10().alpha(0.5),
+ version_control_blame_age_new: orange().dark().step_10(),
+ version_control_blame_age_old: blue().dark().step_10(),
}
}
}
@@ -233,6 +233,8 @@ pub(crate) fn zed_default_dark() -> Theme {
version_control_ignored: crate::gray().light().step_12(),
version_control_conflict_marker_ours: crate::green().light().step_12().alpha(0.5),
version_control_conflict_marker_theirs: crate::blue().light().step_12().alpha(0.5),
+ version_control_blame_age_new: crate::orange().dark().step_9(),
+ version_control_blame_age_old: crate::blue().dark().step_9(),
},
status: StatusColors {
conflict: yellow,
@@ -756,6 +756,14 @@ pub fn theme_colors_refinement(
.as_ref()
.or(this.version_control_conflict_theirs_background.as_ref())
.and_then(|color| try_parse_color(color).ok()),
+ version_control_blame_age_new: this
+ .version_control_blame_age_new
+ .as_ref()
+ .and_then(|color| try_parse_color(color).ok()),
+ version_control_blame_age_old: this
+ .version_control_blame_age_old
+ .as_ref()
+ .and_then(|color| try_parse_color(color).ok()),
}
}
@@ -286,6 +286,11 @@ pub struct ThemeColors {
pub version_control_conflict_marker_ours: Hsla,
/// Represents the "theirs" region of a merge conflict.
pub version_control_conflict_marker_theirs: Hsla,
+
+ /// Blame gutter color for new revisions.
+ pub version_control_blame_age_new: Hsla,
+ /// Blame gutter color for old revisions.
+ pub version_control_blame_age_old: Hsla,
}
#[derive(EnumIter, Debug, Clone, Copy, AsRefStr)]