UI cleanup: plain language, fix relay status display, remove jargon

This commit is contained in:
2026-05-19 23:56:49 -07:00
parent 66d8ff0203
commit d6e1f43152
5 changed files with 35 additions and 32 deletions
+21 -17
View File
@@ -24,11 +24,11 @@ async fn render(state: &AppState) -> anyhow::Result<Html<String>> {
let stats_html = format!(
r#"<div class="stats">
<div class="stat"><div class="val">{}</div><div class="lbl">Indexed</div></div>
<div class="stat"><div class="val">{}</div><div class="lbl">Torrents</div></div>
<div class="stat"><div class="val">{}</div><div class="lbl">Publishers</div></div>
<div class="stat"><div class="val">{}</div><div class="lbl">Queued</div></div>
<div class="stat"><div class="val">{}</div><div class="lbl">In queue</div></div>
<div class="stat"><div class="val">{}</div><div class="lbl">Published</div></div>
<div class="stat"><div class="val" style="font-size:1rem;padding-top:.2rem">{last_seen}</div><div class="lbl">Last ingest</div></div>
<div class="stat"><div class="val" style="font-size:1rem;padding-top:.2rem">{last_seen}</div><div class="lbl">Last activity</div></div>
</div>"#,
stats.torrent_count,
stats.publisher_count,
@@ -47,15 +47,13 @@ async fn render(state: &AppState) -> anyhow::Result<Html<String>> {
relays
.iter()
.map(|r| {
let (dot, ts_str) = match r.last_event {
Some(ts) => ("dot-ok", format!("last event {}", fmt_ts_ago(ts))),
// "no events yet" is normal on a fresh start — the relay is connected
// but kindexr hasn't received any NIP-35 events from it this session.
None => ("dot-dim", "connected — no events received yet".into()),
let ts_str = match r.last_event {
Some(ts) => format!("last event {}", fmt_ts_ago(ts)),
None => "no events yet".into(),
};
format!(
r#"<div class="relay-row">
<span><span class="dot {dot}"></span><span class="relay-url">{url}</span></span>
<span class="relay-url">{url}</span>
<span class="relay-ts">{ts_str}</span>
</div>"#,
url = esc(&r.url),
@@ -64,12 +62,18 @@ async fn render(state: &AppState) -> anyhow::Result<Html<String>> {
.collect()
};
let all = relays.len();
let conn_label = if relay_count as usize == all {
format!("{relay_count} relays connected")
} else {
format!("{relay_count} of {all} relays connected")
};
let relays_html = format!(
r#"<div class="section">
<div class="section-title">Relays — {relay_count} connected / {} configured</div>
<div class="section-title">{conn_label}</div>
<div class="relay-list">{relay_rows}</div>
</div>"#,
relays.len(),
);
// Recent ingest table
@@ -101,7 +105,7 @@ async fn render(state: &AppState) -> anyhow::Result<Html<String>> {
let recent_html = format!(
r#"<div class="section">
<div class="section-title">Recent ingest</div>
<div class="section-title">Recently indexed</div>
<div class="table-wrap">
<table>
<thead><tr><th>Title</th><th>Category</th><th>Publisher</th><th>When</th></tr></thead>
@@ -124,25 +128,25 @@ fn build_network_html(state: &AppState) -> String {
"tor" => (
"badge-warn",
"Tor",
"SOCKS5 → 127.0.0.1:9050 — all outbound traffic routed through Tor".to_string(),
"All connections go through Tor (127.0.0.1:9050)".to_string(),
),
"i2p" => (
"badge-accent",
"I2P",
"SOCKS5 → 127.0.0.1:4446 — all outbound traffic routed through I2P".to_string(),
"All connections go through I2P (127.0.0.1:4446)".to_string(),
),
"socks5" => {
let addr = proxy.url.trim_start_matches("socks5://").trim_start_matches("socks5h://");
(
"badge-accent",
"SOCKS5",
format!("SOCKS5 → {addr} — all outbound traffic proxied"),
format!("All connections go through {addr}"),
)
}
_ => (
"badge-dim",
"Direct",
format!("No proxy — outbound connections use your host's network stack directly"),
"No proxy, using your server's network directly".to_string(),
),
};
@@ -161,7 +165,7 @@ fn build_network_html(state: &AppState) -> String {
<div class="card" style="margin-bottom:.75rem">
<div style="display:flex;gap:1rem;align-items:flex-start;flex-wrap:wrap">
<div style="min-width:160px">
<div style="font-size:.65rem;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);margin-bottom:.3rem">Proxy / anonymity</div>
<div style="font-size:.65rem;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);margin-bottom:.3rem">Network</div>
<span class="badge {proxy_badge_class}" style="font-size:12px;padding:.2rem .6rem">{proxy_label}</span>
<div style="font-size:11px;color:var(--muted);margin-top:.4rem;max-width:440px">{proxy_detail}</div>
</div>
+1 -1
View File
@@ -83,7 +83,7 @@ async fn render(state: &AppState, params: &Params) -> anyhow::Result<Html<String
let pager = pagination(&base_url, page_num, total_pages);
let body = format!(
r#"<h1>Indexed <span style="font-weight:400;color:var(--muted);font-size:.9rem">({total} total)</span></h1>
r#"<h1>Content <span style="font-weight:400;color:var(--muted);font-size:.9rem">({total} total)</span></h1>
{search}
<div class="table-wrap">
<table>
+1 -1
View File
@@ -66,7 +66,7 @@ async fn torrent_blob_handler(
pub fn page(active: &str, title: &str, body: &str) -> axum::response::Html<String> {
let nav = [
("dashboard", "/ui", "Dashboard"),
("indexed", "/ui/indexed", "Indexed"),
("indexed", "/ui/indexed", "Content"),
("publishers", "/ui/publishers", "Publishers"),
("published", "/ui/published", "Published"),
("settings", "/ui/settings", "Settings"),
+2 -2
View File
@@ -39,7 +39,7 @@ async fn render(state: &AppState, params: &Params) -> anyhow::Result<Html<String
let tabs = format!(
r#"<div class="tabs">
<a href="/ui/published?tab=done" class="{c_done}">Published</a>
<a href="/ui/published?tab=pending" class="{c_pend}">Pending queue</a>
<a href="/ui/published?tab=pending" class="{c_pend}">Pending</a>
</div>"#,
c_done = if tab == "done" { "cur" } else { "" },
c_pend = if tab == "pending" { "cur" } else { "" },
@@ -64,7 +64,7 @@ async fn render(state: &AppState, params: &Params) -> anyhow::Result<Html<String
Some(e) => format!(r#"<span class="mono" style="color:var(--danger)" title="{}">[error]</span>"#, esc(e)),
None => {
let sched = fmt_ts_ago(r.scheduled_at);
format!(r#"<span class="mono" style="color:var(--muted)">in {sched}</span>"#)
format!(r#"<span class="mono" style="color:var(--muted)">scheduled {sched}</span>"#)
}
},
};
+10 -11
View File
@@ -47,24 +47,23 @@ async fn render(state: &AppState, params: &ListParams) -> anyhow::Result<Html<St
// Vouch form
let vouch_form = r#"<div class="card">
<div class="card-title">Override publisher trust</div>
<div class="card-title">Set trust level</div>
<form method="POST" action="/ui/publishers/vouch">
<div class="form-row">
<input class="wide mono-in" type="text" name="pubkey"
placeholder="npub1… or 64-char hex pubkey" required>
placeholder="npub1… or hex pubkey" required>
<select name="action">
<option value="trusted">Trusted (score 1.0)</option>
<option value="neutral">Neutral (score 0.5)</option>
<option value="untrusted">Untrusted (score 0.0)</option>
<option value="trusted">Trusted</option>
<option value="neutral">Neutral</option>
<option value="untrusted">Untrusted</option>
<option value="block">Block</option>
</select>
<button type="submit" class="btn-accent">Apply</button>
</div>
<div style="margin-top:.6rem;font-size:11px;color:var(--muted);line-height:1.6">
<strong style="color:var(--text)">Local override only nothing is broadcast to Nostr.</strong>
The <em>Follow depth</em> column is read from your operator pubkey's real Nostr follow list.
This form lets you override trust for anyone regardless of whether you follow them.
Blocking silently drops all future events from that pubkey at ingest.
This is local only, nothing gets posted to Nostr.
Click any publisher row to copy their npub into the box above.
Blocking drops all future posts from that person.
</div>
</form>
</div>"#;
@@ -173,8 +172,8 @@ function fillVouch(el) {{
<div class="table-wrap">
<table>
<thead><tr>
<th>Identity</th><th>Trust</th><th title="How many hops from your operator pubkey's follow list: 0=you, 1=you follow them, 2=someone you follow follows them, —=outside your network">Follow depth</th>
<th>Events</th><th>Reports</th><th>Last seen</th><th>Actions</th>
<th>Publisher</th><th>Trust</th><th title="0=you, 1=you follow them, 2=a follow of yours follows them">Follows</th>
<th>Posts</th><th>Reports</th><th>Last seen</th><th></th>
</tr></thead>
<tbody>{table_rows}</tbody>
</table>