Show person details as lines, with relative and exact time

The first line shows how long ago the position is, also in days, and
the exact time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AuthorKonata <konata@posteo.jp>
Date
Commit54b015c1cfdba6643228c521dac9c4ef26af5485
Parentf82483a
3 files changed, 17 insertions(+), 7 deletions(-)
▾Mweb/src/i18n.rs
@@ -547,6 +547,7 @@ const DE: &[(&str, &str)] = &[
"Passkeys sind für {} eingerichtet, diese Seite ist aber {}. Setze --public-url auf die Adresse, die du verwendest.",
),
("{} (you)", "{} (du)"),
("{} d ago", "vor {} d"),
("{} h ago", "vor {} h"),
("{} min ago", "vor {} min"),
("{} points.", "{} Punkte."),
▾Mweb/src/main.rs
@@ -365,11 +365,20 @@ pub fn fmt_time(ts: i64) -> String {
.into()
}
/// Relative up to a day, then the date and time.
pub fn ago(ts: i64) -> String {
if now_secs() - ts < 86400 {
since(ts)
} else {
fmt_time(ts)
}
}
pub fn since(ts: i64) -> String {
match (now_secs() - ts).max(0) {
d @ 0..60 => tr(&format!("{d} s ago")),
d @ 60..3600 => tr(&format!("{} min ago", d / 60)),
d @ 3600..86400 => tr(&format!("{} h ago", d / 3600)),
_ => fmt_time(ts),
d => tr(&format!("{} d ago", d / 86400)),
}
}
▾Mweb/src/map.rs
@@ -9,7 +9,7 @@ use wasm_bindgen::JsValue;
use wasm_bindgen::prelude::*;
use crate::i18n::tr;
use crate::{ago, fmt_time, http, now_secs};
use crate::{fmt_time, http, now_secs, since};
const OSM: &str =
"&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors";
@@ -587,7 +587,7 @@ pub fn MapPage(#[prop(default = Source::Account)] source: Source) -> impl IntoVi
<li class:selected=move || selected.get() == Some(id) on:click=move |_| select(&p)>
<span class="dot" style:background=color(id)></span>
<span class="name">{name}</span>
<div class="hint">{detail}</div>
<div class="hint">{detail.into_iter().map(|line| view! { <div>{line}</div> }).collect_view()}</div>
</li>
}
})
@@ -662,12 +662,12 @@ fn fit_opts() -> JsValue {
])
}
fn describe(p: &Person) -> String {
fn describe(p: &Person) -> Vec<String> {
let Some(d) = p.last() else {
return tr("no position yet");
return vec![tr("no position yet")];
};
let l = &d.last;
let mut parts = vec![ago(l.ts)];
let mut parts = vec![format!("{} ({})", since(l.ts), fmt_time(l.ts))];
if p.devices.len() > 1 {
parts.push(d.name.clone());
}
@@ -683,5 +683,5 @@ fn describe(p: &Person) -> String {
if let Some(b) = l.battery {
parts.push(tr(&format!("battery {b}%")));
}
parts.join(" · ")
parts
}