diff --git a/Cargo.lock b/Cargo.lock index 416d2a0..69e9eb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,7 +202,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "based" version = "0.1.0" -source = "git+https://git.hydrar.de/jmarya/based?branch=ui#519c2d3e28040601ac37812c9882e54532036b53" +source = "git+https://git.hydrar.de/jmarya/based?branch=ui#069a293e78cfdcda7be8413c25557c9592dbbc9f" dependencies = [ "bcrypt", "chrono", diff --git a/src/archive/mod.rs b/src/archive/mod.rs index 5a89f63..0dbad12 100644 --- a/src/archive/mod.rs +++ b/src/archive/mod.rs @@ -300,13 +300,26 @@ pub async fn index_document(doc: &Document) { pub struct DocumentIndex {} impl DocumentIndex { - pub async fn get_documents_of_day(day: NaiveDate) -> HashMap> { - let res: Vec<(String, String)> = + pub async fn get_documents_of_day( + day: NaiveDate, + domain: Option<&str>, + ) -> HashMap> { + let res: Vec<(String, String)> = if let Some(domain) = domain { + sqlx::query_as( + "SELECT domain, path FROM document_index WHERE version = $1 WHERE domain = $2", + ) + .bind(day) + .bind(domain) + .fetch_all(get_pg!()) + .await + .unwrap() + } else { sqlx::query_as("SELECT domain, path FROM document_index WHERE version = $1") .bind(day) .fetch_all(get_pg!()) .await - .unwrap(); + .unwrap() + }; let mut ret = HashMap::new(); diff --git a/src/main.rs b/src/main.rs index 2933ae5..927c38f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -183,14 +183,11 @@ pub fn get_shell() -> Shell { Shell::new( Nothing(), Nothing(), - Background(MinHeight( - ScreenValue::screen, - Padding(Text("").white()).top(ScreenValue::_8), - )) - .color(Zinc::_950), + Background(MinHeight(ScreenValue::screen, Text("").white())).color(Zinc::_950), ) .use_ui() .with_navbar(NavBar("Web Archive")) } // TODO : archive cleanup code +// TODO : archive pkg code -> tar.gz diff --git a/src/pages/mod.rs b/src/pages/mod.rs index 4041b5f..87f3bd1 100644 --- a/src/pages/mod.rs +++ b/src/pages/mod.rs @@ -8,7 +8,7 @@ use based::{ }, ui::{ components::{ - prelude::{InfinityScroll, Timeline, TimelineElement}, + prelude::{InfinityScroll, Timeline, TimelineElement, Tooltip}, ColoredSpinner, Search, Shell, }, primitives::flex::Column, @@ -34,6 +34,7 @@ use webarc::{ const SEARCH_BAR_STYLE: &str = "w-full px-4 mb-4 py-2 text-white bg-black border-2 border-neon-blue placeholder-neon-blue focus:ring-2 focus:ring-neon-pink focus:outline-none font-mono text-lg"; +#[allow(non_snake_case)] pub fn WebsiteIcon(domain: &str) -> PreEscaped { html! { h2 class="text-xl font-bold mb-4 -ml-2 flex items-center w-fit" { @@ -43,6 +44,25 @@ pub fn WebsiteIcon(domain: &str) -> PreEscaped { } } +fn time_ago(naive_datetime: &chrono::NaiveDate) -> String { + let now = chrono::Local::now().date_naive(); + let duration = now.signed_duration_since(*naive_datetime); + + if duration.num_seconds() < 60 { + format!("{} seconds ago", duration.num_seconds()) + } else if duration.num_minutes() < 60 { + format!("{} minutes ago", duration.num_minutes()) + } else if duration.num_hours() < 24 { + format!("{} hours ago", duration.num_hours()) + } else if duration.num_days() < 30 { + format!("{} days ago", duration.num_days()) + } else if duration.num_days() < 365 { + format!("{} months ago", duration.num_days() / 30) + } else { + format!("{} years ago", duration.num_days() / 365) + } +} + pub fn build_timeline( domains: HashMap>, the_day: NaiveDate, @@ -58,7 +78,7 @@ pub fn build_timeline( for key in sorted_keys { let (domain, paths) = (key, domains.get(key).unwrap()); tl = tl.add_element(TimelineElement::new( - &the_day.to_string(), + Tooltip(time_ago(&the_day), Text(&the_day.to_string())), WebsiteIcon(domain), Column( paths @@ -82,18 +102,19 @@ pub fn build_timeline( tl.render_with_class("") } -pub async fn get_domains(before: &str) -> HashMap> { +pub async fn get_domains(before: &str, domain: Option<&str>) -> HashMap> { let today = NaiveDate::parse_from_str(before, "%Y-%m-%d").unwrap(); - DocumentIndex::get_documents_of_day(today).await + DocumentIndex::get_documents_of_day(today, domain).await } pub async fn get_domains_lookback( before: &str, mut days: u64, + domain: Option<&str>, ) -> (HashMap>, NaiveDate) { let mut the_day = NaiveDate::parse_from_str(before, "%Y-%m-%d").unwrap(); while days > 0 { - let domains = get_domains(&the_day.to_string()).await; + let domains = get_domains(&the_day.to_string(), domain).await; if !domains.is_empty() { return (domains, the_day); @@ -106,18 +127,19 @@ pub async fn get_domains_lookback( (HashMap::new(), the_day) } -#[get("/timeline?")] +#[get("/timeline?&")] pub async fn timeline_route( ctx: RequestContext, shell: &State, before: Option<&str>, + domain: Option<&str>, ) -> StringResponse { let today = chrono::Local::now().date_naive(); let (domains, day) = if let Some(before) = before { - get_domains_lookback(before, 30 * 12).await + get_domains_lookback(before, 30 * 12, domain).await } else { - get_domains_lookback(&today.to_string(), 30 * 12).await + get_domains_lookback(&today.to_string(), 30 * 12, domain).await }; if domains.is_empty() { @@ -382,11 +404,12 @@ pub async fn render_website( if time.is_none() { let versions = document.versions(); - let latest_version = versions.first()?; - if let Some(outdated) = get_config().get_outdated(domain) { - if is_older_than(latest_version, outdated) { - log::info!("Document {domain} / {path} is outdated, redownloading"); - return redownload(&arc, domain, path, &document, &shell).await; + if let Some(latest_version) = versions.first() { + if let Some(outdated) = get_config().get_outdated(domain) { + if is_older_than(latest_version, outdated) { + log::info!("Document {domain} / {path} is outdated, redownloading"); + return redownload(&arc, domain, path, &document, &shell).await; + } } } }