Show archive context in shell
This commit is contained in:
@@ -0,0 +1,109 @@
|
|||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
|
use ely_domain::{ArchiveSource, ArchivedTab, BrowserTab, Profile, Space};
|
||||||
|
|
||||||
|
pub(super) fn archive_detail_label(
|
||||||
|
archived_tab: &ArchivedTab,
|
||||||
|
spaces: &[Space],
|
||||||
|
profiles: &[Profile],
|
||||||
|
) -> String {
|
||||||
|
archive_detail_label_for(archived_tab, spaces, profiles, SystemTime::now())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn archive_detail_label_for(
|
||||||
|
archived_tab: &ArchivedTab,
|
||||||
|
spaces: &[Space],
|
||||||
|
profiles: &[Profile],
|
||||||
|
now: SystemTime,
|
||||||
|
) -> String {
|
||||||
|
let tab = archived_tab.tab();
|
||||||
|
format!(
|
||||||
|
"{} - {} - {} - {} - {}",
|
||||||
|
tab.display_url(),
|
||||||
|
archive_space_label(tab, spaces),
|
||||||
|
archive_profile_label(tab, profiles),
|
||||||
|
archive_source_label(archived_tab.source()),
|
||||||
|
archived_at_label_for(archived_tab.archived_at(), now)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn archive_source_label(source: &ArchiveSource) -> &'static str {
|
||||||
|
match source {
|
||||||
|
ArchiveSource::ManualClose => "Closed",
|
||||||
|
ArchiveSource::AutoArchive => "Auto archived",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn archive_space_label(tab: &BrowserTab, spaces: &[Space]) -> String {
|
||||||
|
spaces
|
||||||
|
.iter()
|
||||||
|
.find(|space| space.id() == tab.space_id())
|
||||||
|
.map(|space| format!("Space: {}", space.name()))
|
||||||
|
.unwrap_or_else(|| format!("Space: {}", tab.space_id().as_str()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn archive_profile_label(tab: &BrowserTab, profiles: &[Profile]) -> String {
|
||||||
|
profiles
|
||||||
|
.iter()
|
||||||
|
.find(|profile| profile.id() == tab.profile_id())
|
||||||
|
.map(|profile| format!("Profile: {}", profile.name()))
|
||||||
|
.unwrap_or_else(|| format!("Profile: {}", tab.profile_id().as_str()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn archived_at_label_for(archived_at: SystemTime, now: SystemTime) -> String {
|
||||||
|
let Ok(elapsed) = now.duration_since(archived_at) else {
|
||||||
|
return "Just now".to_string();
|
||||||
|
};
|
||||||
|
|
||||||
|
let seconds = elapsed.as_secs();
|
||||||
|
if seconds < 60 {
|
||||||
|
return "Just now".to_string();
|
||||||
|
}
|
||||||
|
if seconds < 3_600 {
|
||||||
|
return archive_elapsed_label(seconds / 60, "min");
|
||||||
|
}
|
||||||
|
if seconds < 86_400 {
|
||||||
|
return archive_elapsed_label(seconds / 3_600, "hr");
|
||||||
|
}
|
||||||
|
if seconds < 604_800 {
|
||||||
|
return archive_elapsed_label(seconds / 86_400, "day");
|
||||||
|
}
|
||||||
|
"Earlier".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn archive_elapsed_label(value: u64, unit: &str) -> String {
|
||||||
|
match value {
|
||||||
|
1 => format!("1 {unit} ago"),
|
||||||
|
count => format!("{count} {unit}s ago"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::{error::Error, time::Duration};
|
||||||
|
|
||||||
|
use ely_domain::{ProfileKind, TabId, UrlText};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn archive_detail_label_includes_space_profile_source_and_time() -> Result<(), Box<dyn Error>> {
|
||||||
|
let profile = Profile::new("Research", 0x9fc9a2, ProfileKind::Standard);
|
||||||
|
let space = Space::new("Work", "W", 0xf54e00, profile.id().clone(), 0);
|
||||||
|
let tab = BrowserTab::new(
|
||||||
|
TabId::new(),
|
||||||
|
space.id().clone(),
|
||||||
|
profile.id().clone(),
|
||||||
|
"Research",
|
||||||
|
UrlText::parse("https://example.com/research")?,
|
||||||
|
);
|
||||||
|
let archived_tab = ArchivedTab::new(tab, ArchiveSource::ManualClose);
|
||||||
|
let now = archived_tab.archived_at() + Duration::from_secs(7_200);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
archive_detail_label_for(&archived_tab, &[space], &[profile], now),
|
||||||
|
"example.com - Space: Work - Profile: Research - Closed - 2 hrs ago"
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ mod task_manager;
|
|||||||
|
|
||||||
use ely_browser_core::BrowserSnapshot;
|
use ely_browser_core::BrowserSnapshot;
|
||||||
use ely_design_system::{colors, spacing};
|
use ely_design_system::{colors, spacing};
|
||||||
use ely_domain::{ArchiveSource, ArchivedTab, BrowserTab};
|
use ely_domain::{ArchivedTab, BrowserTab};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AnyElement, Context, InteractiveElement, IntoElement, ParentElement, SharedString,
|
AnyElement, Context, InteractiveElement, IntoElement, ParentElement, SharedString,
|
||||||
StatefulInteractiveElement, Styled, div, px, rgb,
|
StatefulInteractiveElement, Styled, div, px, rgb,
|
||||||
@@ -34,6 +34,7 @@ use gpui::{
|
|||||||
use gpui_component::{IconName, StyledExt, scroll::ScrollableElement};
|
use gpui_component::{IconName, StyledExt, scroll::ScrollableElement};
|
||||||
|
|
||||||
use super::ElyShell;
|
use super::ElyShell;
|
||||||
|
use super::archive_labels::archive_detail_label;
|
||||||
|
|
||||||
impl ElyShell {
|
impl ElyShell {
|
||||||
pub(super) fn render_web_canvas(
|
pub(super) fn render_web_canvas(
|
||||||
@@ -147,14 +148,9 @@ impl ElyShell {
|
|||||||
.overflow_y_scrollbar()
|
.overflow_y_scrollbar()
|
||||||
.border_t_1()
|
.border_t_1()
|
||||||
.border_color(rgb(colors::HAIRLINE))
|
.border_color(rgb(colors::HAIRLINE))
|
||||||
.children(
|
.children(snapshot.archived_tabs.iter().rev().enumerate().map(
|
||||||
snapshot
|
|(index, archived_tab)| self.render_archive_row(index, archived_tab, snapshot, cx),
|
||||||
.archived_tabs
|
))
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(index, archived_tab)| self.render_archive_row(index, archived_tab, cx)),
|
|
||||||
)
|
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,10 +158,12 @@ impl ElyShell {
|
|||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
archived_tab: &ArchivedTab,
|
archived_tab: &ArchivedTab,
|
||||||
|
snapshot: &BrowserSnapshot,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> AnyElement {
|
) -> AnyElement {
|
||||||
let tab = archived_tab.tab();
|
let tab = archived_tab.tab();
|
||||||
let tab_id = tab.id().clone();
|
let tab_id = tab.id().clone();
|
||||||
|
let detail = archive_detail_label(archived_tab, &snapshot.spaces, &snapshot.profiles);
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.id(SharedString::from(format!("archive-{index}")))
|
.id(SharedString::from(format!("archive-{index}")))
|
||||||
@@ -196,13 +194,7 @@ impl ElyShell {
|
|||||||
.text_color(rgb(colors::INK))
|
.text_color(rgb(colors::INK))
|
||||||
.child(tab.title().to_string()),
|
.child(tab.title().to_string()),
|
||||||
)
|
)
|
||||||
.child(div().text_xs().truncate().text_color(rgb(colors::MUTED)).child(
|
.child(div().text_xs().truncate().text_color(rgb(colors::MUTED)).child(detail)),
|
||||||
format!(
|
|
||||||
"{} - {}",
|
|
||||||
tab.display_url(),
|
|
||||||
archive_source_label(archived_tab.source())
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
)
|
)
|
||||||
.child(div().text_color(rgb(colors::MUTED_SOFT)).child(IconName::Undo2))
|
.child(div().text_color(rgb(colors::MUTED_SOFT)).child(IconName::Undo2))
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
@@ -251,10 +243,3 @@ fn render_tab_status(tab: &BrowserTab) -> String {
|
|||||||
url => url.to_string(),
|
url => url.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn archive_source_label(source: &ArchiveSource) -> &'static str {
|
|
||||||
match source {
|
|
||||||
ArchiveSource::ManualClose => "Closed",
|
|
||||||
ArchiveSource::AutoArchive => "Auto archived",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
mod archive_labels;
|
||||||
mod bookmarks;
|
mod bookmarks;
|
||||||
mod downloads;
|
mod downloads;
|
||||||
mod history;
|
mod history;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use ely_browser_core::BrowserSnapshot;
|
use ely_browser_core::BrowserSnapshot;
|
||||||
use ely_design_system::{ELY_THEME, colors, spacing};
|
use ely_design_system::{ELY_THEME, colors, spacing};
|
||||||
use ely_domain::{ArchiveSource, ArchivedTab, BrowserTab, Profile, Space};
|
use ely_domain::{ArchivedTab, BrowserTab, Profile, Space};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AnyElement, Context, InteractiveElement, IntoElement, ParentElement, Render, SharedString,
|
AnyElement, Context, InteractiveElement, IntoElement, ParentElement, Render, SharedString,
|
||||||
StatefulInteractiveElement, Styled, Window, div, px, rgb,
|
StatefulInteractiveElement, Styled, Window, div, px, rgb,
|
||||||
@@ -12,7 +12,7 @@ use gpui_component::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::sidebar::{collapsed_sidebar_active, render_command_bar_identity};
|
use super::sidebar::{collapsed_sidebar_active, render_command_bar_identity};
|
||||||
use super::{ElyShell, ShellState};
|
use super::{ElyShell, ShellState, archive_labels::archive_detail_label};
|
||||||
|
|
||||||
impl Render for ElyShell {
|
impl Render for ElyShell {
|
||||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
@@ -195,7 +195,7 @@ impl ElyShell {
|
|||||||
.archived_tabs
|
.archived_tabs
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.map(|archived_tab| self.render_archived_row(archived_tab, cx)),
|
.map(|archived_tab| self.render_archived_row(archived_tab, snapshot, cx)),
|
||||||
)
|
)
|
||||||
.child(div().flex_1())
|
.child(div().flex_1())
|
||||||
.child(section_label("Profile"))
|
.child(section_label("Profile"))
|
||||||
@@ -383,10 +383,12 @@ impl ElyShell {
|
|||||||
fn render_archived_row(
|
fn render_archived_row(
|
||||||
&mut self,
|
&mut self,
|
||||||
archived_tab: &ArchivedTab,
|
archived_tab: &ArchivedTab,
|
||||||
|
snapshot: &BrowserSnapshot,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> AnyElement {
|
) -> AnyElement {
|
||||||
let tab = archived_tab.tab();
|
let tab = archived_tab.tab();
|
||||||
let tab_id = tab.id().clone();
|
let tab_id = tab.id().clone();
|
||||||
|
let detail = archive_detail_label(archived_tab, &snapshot.spaces, &snapshot.profiles);
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.id(SharedString::from(format!("archived-{}", tab.id().as_str())))
|
.id(SharedString::from(format!("archived-{}", tab.id().as_str())))
|
||||||
@@ -419,11 +421,7 @@ impl ElyShell {
|
|||||||
.text_color(rgb(colors::INK))
|
.text_color(rgb(colors::INK))
|
||||||
.child(tab.title().to_string()),
|
.child(tab.title().to_string()),
|
||||||
)
|
)
|
||||||
.child(div().text_xs().text_color(rgb(colors::MUTED)).child(format!(
|
.child(div().text_xs().text_color(rgb(colors::MUTED)).child(detail)),
|
||||||
"{} - {}",
|
|
||||||
tab.display_url(),
|
|
||||||
archive_source_label(archived_tab.source())
|
|
||||||
))),
|
|
||||||
)
|
)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
@@ -455,13 +453,6 @@ fn active_sidebar_width(snapshot: &BrowserSnapshot) -> Result<f32, String> {
|
|||||||
Ok(f32::from(active_space.sidebar_width_px()))
|
Ok(f32::from(active_space.sidebar_width_px()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn archive_source_label(source: &ArchiveSource) -> &'static str {
|
|
||||||
match source {
|
|
||||||
ArchiveSource::ManualClose => "Closed",
|
|
||||||
ArchiveSource::AutoArchive => "Auto archived",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sidebar_tab_detail(tab: &BrowserTab, profiles: &[Profile]) -> String {
|
fn sidebar_tab_detail(tab: &BrowserTab, profiles: &[Profile]) -> String {
|
||||||
format!("{} - {}", tab.display_url(), tab_profile_label(tab, profiles))
|
format!("{} - {}", tab.display_url(), tab_profile_label(tab, profiles))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
│ ● New Tab │ │
|
│ ● New Tab │ │
|
||||||
│ Archive │ │
|
│ Archive │ │
|
||||||
│ ↶ servo.org │ │
|
│ ↶ servo.org │ │
|
||||||
|
│ Space: Work - Profile: Default - Closed - Just now │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ Profile │ Ready │
|
│ Profile │ Ready │
|
||||||
│ Default │ │
|
│ Default │ │
|
||||||
|
|||||||
Reference in New Issue
Block a user