commit d71cb08af396944efe22ebcfb8404b9b826ec6e4
parent 01cf302deda0489ffcf2d5b5ffbf1096b7e1b1e9
Author: alltheseas <alltheseas@users.noreply.github.com>
Date: Thu, 23 Oct 2025 16:43:05 -0500
Address feedback on relay queries and mobile layout
Diffstat:
3 files changed, 69 insertions(+), 65 deletions(-)
diff --git a/assets/damus.css b/assets/damus.css
@@ -268,6 +268,8 @@ a:hover {
.damus-note-body {
font-size: 1.05rem;
line-height: 1.7;
+ word-break: break-word;
+ overflow-wrap: anywhere;
}
.damus-note-body img {
@@ -360,6 +362,8 @@ a:hover {
line-height: 1.7;
color: var(--damus-muted);
white-space: pre-wrap;
+ word-break: break-word;
+ overflow-wrap: anywhere;
}
.damus-relays {
diff --git a/src/html.rs b/src/html.rs
@@ -50,10 +50,10 @@ fn merge_relay_entry(relays: &mut Vec<RelayEntry>, url: &str, marker: Option<&st
});
}
-const ICON_KEY_CIRCLE: &str = r#"<svg viewBox=\"0 0 18 18\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M11.3058 6.37751C11.4643 7.01298 11.0775 7.65657 10.4421 7.81501C9.80661 7.97345 9.16302 7.58674 9.00458 6.95127C8.84614 6.3158 9.23285 5.67221 9.86831 5.51377C10.5038 5.35533 11.1474 5.74204 11.3058 6.37751Z\" fill=\"currentColor\"/><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 0 9 0C4.02944 0 0 4.02944 0 9C0 13.9706 4.02944 18 9 18ZM10.98 10.0541C12.8102 9.59778 13.9381 7.80131 13.4994 6.04155C13.0606 4.28178 11.2213 3.22513 9.39116 3.68144C7.56101 4.13774 6.43306 5.93422 6.87182 7.69398C6.97647 8.11372 7.1608 8.49345 7.40569 8.8222L5.3739 12.0582C5.30459 12.1686 5.28324 12.3025 5.31477 12.4289L5.73708 14.1228C5.7691 14.2511 5.89912 14.3293 6.02751 14.2973L7.81697 13.8511C7.93712 13.8211 8.04101 13.7458 8.10686 13.641L10.295 10.1559C10.5216 10.1446 10.7509 10.1112 10.98 10.0541Z\" fill=\"currentColor\"/></svg>"#;
-const ICON_CONTACT_CIRCLE: &str = r#"<svg viewBox=\"0 0 18 18\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 0 9 0C4.02944 0 0 4.02944 0 9C0 13.9706 4.02944 18 9 18ZM11.6667 6.66667C11.6667 8.13943 10.4728 9.33333 9.00004 9.33333C7.52728 9.33333 6.33337 8.13943 6.33337 6.66667C6.33337 5.19391 7.52728 4 9.00004 4C10.4728 4 11.6667 5.19391 11.6667 6.66667ZM13.6667 12.3333C13.6667 13.2538 11.5774 14 9.00004 14C6.42271 14 4.33337 13.2538 4.33337 12.3333C4.33337 11.4129 6.42271 10.6667 9.00004 10.6667C11.5774 10.6667 13.6667 11.4129 13.6667 12.3333Z\" fill=\"currentColor\"/></svg>"#;
-const ICON_LINK_CIRCLE: &str = r#"<svg viewBox=\"0 0 18 18\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 0 9 0C4.02944 0 0 4.02944 0 9C0 13.9706 4.02944 18 9 18ZM10.5074 5.12274C10.7369 4.89317 11.1091 4.89317 11.3387 5.12274L12.8772 6.6612C13.1067 6.89077 13.1067 7.26298 12.8772 7.49256L10.9541 9.41563C10.7588 9.6109 10.7588 9.92748 10.9541 10.1227C11.1494 10.318 11.4659 10.318 11.6612 10.1227L13.5843 8.19966C14.2044 7.57957 14.2044 6.57419 13.5843 5.95409L12.0458 4.41563C11.4257 3.79554 10.4203 3.79554 9.80025 4.41563L7.87718 6.33871C7.68191 6.53397 7.68191 6.85055 7.87718 7.04582C8.07244 7.24108 8.38902 7.24108 8.58428 7.04582L10.5074 5.12274ZM11.0843 7.62274C11.2795 7.42748 11.2795 7.1109 11.0843 6.91563C10.889 6.72037 10.5724 6.72037 10.3772 6.91563L7.10794 10.1849C6.91268 10.3801 6.91268 10.6967 7.10794 10.892C7.30321 11.0872 7.61979 11.0872 7.81505 10.892L11.0843 7.62274ZM7.04582 8.5843C7.24108 8.38904 7.24108 8.07246 7.04582 7.8772C6.85055 7.68194 6.53397 7.68194 6.33871 7.8772L4.41563 9.80027C3.79554 10.4204 3.79554 11.4257 4.41563 12.0458L5.9541 13.5843C6.57419 14.2044 7.57957 14.2044 8.19966 13.5843L10.1227 11.6612C10.318 11.466 10.318 11.1494 10.1227 10.9541C9.92748 10.7589 9.6109 10.7589 9.41563 10.9541L7.49256 12.8772C7.26299 13.1068 6.89077 13.1068 6.6612 12.8772L5.12274 11.3387C4.89317 11.1092 4.89317 10.737 5.12274 10.5074L7.04582 8.5843Z\" fill=\"currentColor\"/></svg>"#;
-const ICON_BITCOIN: &str = r#"<svg viewBox=\"0 0 18 18\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8.28295 7.96658L8.23361 7.95179L8.76146 5.8347C8.81784 5.84928 8.88987 5.86543 8.97324 5.88412C9.67913 6.04237 11.1984 6.38297 10.9233 7.49805C10.6279 8.67114 8.87435 8.14427 8.28295 7.96658Z\" fill=\"currentColor\"/><path d=\"M7.3698 11.4046L7.4555 11.43C8.18407 11.6467 10.2516 12.2615 10.532 11.0972C10.8209 9.97593 8.96224 9.53925 8.13013 9.34375C8.0389 9.32232 7.96002 9.30378 7.89765 9.28756L7.3698 11.4046Z\" fill=\"currentColor\"/><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 0 9 0C4.02944 0 0 4.02944 0 9C0 13.9706 4.02944 18 9 18ZM12.8732 7.61593C13.0794 6.31428 12.1803 5.63589 10.9322 5.17799L11.3709 3.40745L10.3814 3.16221L9.95392 4.88751C9.88913 4.87105 9.82482 4.85441 9.76074 4.83784C9.56538 4.78731 9.3721 4.73731 9.17436 4.69431L9.6018 2.96901L8.58479 2.71696L8.15735 4.44226L6.13863 3.94193L5.847 5.12223C5.847 5.12223 6.59551 5.285 6.56824 5.30098C6.96889 5.40897 7.03686 5.69278 7.01489 5.90971L6.50629 7.91664L5.80746 10.7404C5.75255 10.8744 5.61847 11.0659 5.34426 10.9993C5.35573 11.012 4.61643 10.8087 4.61643 10.8087L4.12964 12.0541L6.08834 12.5875L5.65196 14.3489L6.63523 14.5926L7.07161 12.8312C7.22991 12.8767 7.38989 12.9139 7.54471 12.95C7.66051 12.9769 7.77355 13.0032 7.8807 13.0318L7.44432 14.7931L8.42939 15.0373L8.86577 13.2759C10.5611 13.5993 11.841 13.448 12.4129 11.7791C12.8726 10.4484 12.4427 9.68975 11.5496 9.18998C12.2207 9.02654 12.7174 8.56346 12.8732 7.61593Z\" fill=\"currentColor\"/></svg>"#;
+const ICON_KEY_CIRCLE: &str = r#"<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M11.3058 6.37751C11.4643 7.01298 11.0775 7.65657 10.4421 7.81501C9.80661 7.97345 9.16302 7.58674 9.00458 6.95127C8.84614 6.3158 9.23285 5.67221 9.86831 5.51377C10.5038 5.35533 11.1474 5.74204 11.3058 6.37751Z" fill="currentColor"/><path fill-rule="evenodd" clip-rule="evenodd" d="M9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 0 9 0C4.02944 0 0 4.02944 0 9C0 13.9706 4.02944 18 9 18ZM10.98 10.0541C12.8102 9.59778 13.9381 7.80131 13.4994 6.04155C13.0606 4.28178 11.2213 3.22513 9.39116 3.68144C7.56101 4.13774 6.43306 5.93422 6.87182 7.69398C6.97647 8.11372 7.1608 8.49345 7.40569 8.8222L5.3739 12.0582C5.30459 12.1686 5.28324 12.3025 5.31477 12.4289L5.73708 14.1228C5.7691 14.2511 5.89912 14.3293 6.02751 14.2973L7.81697 13.8511C7.93712 13.8211 8.04101 13.7458 8.10686 13.641L10.295 10.1559C10.5216 10.1446 10.7509 10.1112 10.98 10.0541Z" fill="currentColor"/></svg>"#;
+const ICON_CONTACT_CIRCLE: &str = r#"<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 0 9 0C4.02944 0 0 4.02944 0 9C0 13.9706 4.02944 18 9 18ZM11.6667 6.66667C11.6667 8.13943 10.4728 9.33333 9.00004 9.33333C7.52728 9.33333 6.33337 8.13943 6.33337 6.66667C6.33337 5.19391 7.52728 4 9.00004 4C10.4728 4 11.6667 5.19391 11.6667 6.66667ZM13.6667 12.3333C13.6667 13.2538 11.5774 14 9.00004 14C6.42271 14 4.33337 13.2538 4.33337 12.3333C4.33337 11.4129 6.42271 10.6667 9.00004 10.6667C11.5774 10.6667 13.6667 11.4129 13.6667 12.3333Z" fill="currentColor"/></svg>"#;
+const ICON_LINK_CIRCLE: &str = r#"<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 0 9 0C4.02944 0 0 4.02944 0 9C0 13.9706 4.02944 18 9 18ZM10.5074 5.12274C10.7369 4.89317 11.1091 4.89317 11.3387 5.12274L12.8772 6.6612C13.1067 6.89077 13.1067 7.26298 12.8772 7.49256L10.9541 9.41563C10.7588 9.6109 10.7588 9.92748 10.9541 10.1227C11.1494 10.318 11.4659 10.318 11.6612 10.1227L13.5843 8.19966C14.2044 7.57957 14.2044 6.57419 13.5843 5.95409L12.0458 4.41563C11.4257 3.79554 10.4203 3.79554 9.80025 4.41563L7.87718 6.33871C7.68191 6.53397 7.68191 6.85055 7.87718 7.04582C8.07244 7.24108 8.38902 7.24108 8.58428 7.04582L10.5074 5.12274ZM11.0843 7.62274C11.2795 7.42748 11.2795 7.1109 11.0843 6.91563C10.889 6.72037 10.5724 6.72037 10.3772 6.91563L7.10794 10.1849C6.91268 10.3801 6.91268 10.6967 7.10794 10.892C7.30321 11.0872 7.61979 11.0872 7.81505 10.892L11.0843 7.62274ZM7.04582 8.5843C7.24108 8.38904 7.24108 8.07246 7.04582 7.8772C6.85055 7.68194 6.53397 7.68194 6.33871 7.8772L4.41563 9.80027C3.79554 10.4204 3.79554 11.4257 4.41563 12.0458L5.9541 13.5843C6.57419 14.2044 7.57957 14.2044 8.19966 13.5843L10.1227 11.6612C10.318 11.466 10.318 11.1494 10.1227 10.9541C9.92748 10.7589 9.6109 10.7589 9.41563 10.9541L7.49256 12.8772C7.26299 13.1068 6.89077 13.1068 6.6612 12.8772L5.12274 11.3387C4.89317 11.1092 4.89317 10.737 5.12274 10.5074L7.04582 8.5843Z" fill="currentColor"/></svg>"#;
+const ICON_BITCOIN: &str = r#"<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.28295 7.96658L8.23361 7.95179L8.76146 5.8347C8.81784 5.84928 8.88987 5.86543 8.97324 5.88412C9.67913 6.04237 11.1984 6.38297 10.9233 7.49805C10.6279 8.67114 8.87435 8.14427 8.28295 7.96658Z" fill="currentColor"/><path d="M7.3698 11.4046L7.4555 11.43C8.18407 11.6467 10.2516 12.2615 10.532 11.0972C10.8209 9.97593 8.96224 9.53925 8.13013 9.34375C8.0389 9.32232 7.96002 9.30378 7.89765 9.28756L7.3698 11.4046Z" fill="currentColor"/><path fill-rule="evenodd" clip-rule="evenodd" d="M9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 0 9 0C4.02944 0 0 4.02944 0 9C0 13.9706 4.02944 18 9 18ZM12.8732 7.61593C13.0794 6.31428 12.1803 5.63589 10.9322 5.17799L11.3709 3.40745L10.3814 3.16221L9.95392 4.88751C9.88913 4.87105 9.82482 4.85441 9.76074 4.83784C9.56538 4.78731 9.3721 4.73731 9.17436 4.69431L9.6018 2.96901L8.58479 2.71696L8.15735 4.44226L6.13863 3.94193L5.847 5.12223C5.847 5.12223 6.59551 5.285 6.56824 5.30098C6.96889 5.40897 7.03686 5.69278 7.01489 5.90971L6.50629 7.91664L5.80746 10.7404C5.75255 10.8744 5.61847 11.0659 5.34426 10.9993C5.35573 11.012 4.61643 10.8087 4.61643 10.8087L4.12964 12.0541L6.08834 12.5875L5.65196 14.3489L6.63523 14.5926L7.07161 12.8312C7.22991 12.8767 7.38989 12.9139 7.54471 12.95C7.66051 12.9769 7.77355 13.0032 7.8807 13.0318L7.44432 14.7931L8.42939 15.0373L8.86577 13.2759C10.5611 13.5993 11.841 13.448 12.4129 11.7791C12.8726 10.4484 12.4427 9.68975 11.5496 9.18998C12.2207 9.02654 12.7174 8.56346 12.8732 7.61593Z" fill="currentColor"/></svg>"#;
fn blocktype_name(blocktype: &BlockType) -> &'static str {
match blocktype {
BlockType::MentionBech32 => "mention",
diff --git a/src/render.rs b/src/render.rs
@@ -8,7 +8,10 @@ use egui::{
Color32, FontFamily, FontId, Mesh, Rect, RichText, Rounding, Shape, TextureHandle, Vec2,
Visuals,
};
-use nostr::event::kind::Kind;
+use nostr::event::{
+ kind::Kind,
+ tag::{TagKind, TagStandard},
+};
use nostr::types::{RelayUrl, SingleLetterTag, Timestamp};
use nostr_sdk::async_utility::futures_util::StreamExt;
use nostr_sdk::nips::nip19::Nip19;
@@ -510,23 +513,28 @@ impl RenderData {
fn collect_relay_hints(event: &Event) -> Vec<RelayUrl> {
let mut relays = Vec::new();
- for tag in event.tags.as_slice() {
- let parts = tag.as_slice();
- if parts.is_empty() {
- continue;
- }
- let tag_name = parts[0].as_str();
- let candidate = if matches!(tag_name, "r" | "relay" | "relays") {
- tag.content()
- } else if event.kind == Kind::ContactList {
- parts.get(2).map(|s| s.as_str())
- } else {
- None
+ for tag in event.tags.iter() {
+ let candidate = match tag.kind() {
+ TagKind::Relay | TagKind::Relays => tag.content(),
+ TagKind::SingleLetter(letter) if letter.as_char() == 'r' => tag.content(),
+ _ if event.kind == Kind::ContactList => {
+ if let Some(TagStandard::PublicKey {
+ relay_url: Some(url),
+ ..
+ }) = tag.as_standardized()
+ {
+ Some(url.as_str())
+ } else {
+ tag.as_slice().get(2).map(|value| value.as_str())
+ }
+ }
+ _ => None,
};
let Some(url) = candidate else {
continue;
};
+
if url.is_empty() {
continue;
}
@@ -581,32 +589,34 @@ async fn collect_profile_relays(
.build(),
);
- for filter in [relay_filter, contact_filter] {
- let mut stream = relay_pool
- .stream_events(vec![filter.clone()], &[], Duration::from_millis(2000))
- .await?;
- while let Some(event) = stream.next().await {
- if let Err(err) = ndb.process_event(&event.as_json()) {
- error!("error processing relay discovery event: {err}");
- }
+ let mut stream = relay_pool
+ .stream_events(
+ vec![relay_filter, contact_filter],
+ &[],
+ Duration::from_millis(2000),
+ )
+ .await?;
+ while let Some(event) = stream.next().await {
+ if let Err(err) = ndb.process_event(&event.as_json()) {
+ error!("error processing relay discovery event: {err}");
+ }
- let hints = collect_relay_hints(&event);
- if hints.is_empty() {
- continue;
- }
+ let hints = collect_relay_hints(&event);
+ if hints.is_empty() {
+ continue;
+ }
- let mut fresh = Vec::new();
- for hint in hints {
- let key = hint.to_string();
- if known.insert(key) {
- targets.push(hint.clone());
- fresh.push(hint);
- }
+ let mut fresh = Vec::new();
+ for hint in hints {
+ let key = hint.to_string();
+ if known.insert(key) {
+ targets.push(hint.clone());
+ fresh.push(hint);
}
+ }
- if !fresh.is_empty() {
- relay_pool.ensure_relays(fresh).await?;
- }
+ if !fresh.is_empty() {
+ relay_pool.ensure_relays(fresh).await?;
}
}
@@ -723,7 +733,7 @@ pub fn get_render_data(ndb: &Ndb, txn: &Transaction, nip19: &Nip19) -> Result<Re
NoteRenderData::Address {
author,
kind,
- identifier: identifier.clone(),
+ identifier,
}
}
};
@@ -1067,10 +1077,10 @@ mod tests {
use super::*;
use nostr::nips::nip01::Coordinate;
use nostr::prelude::{EventBuilder, Keys, Tag};
- use nostrdb::Config;
+ use nostrdb::{Config, Filter};
use std::fs;
use std::path::PathBuf;
- use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
+ use std::time::{SystemTime, UNIX_EPOCH};
fn temp_db_dir(prefix: &str) -> PathBuf {
let base = PathBuf::from("target/test-dbs");
@@ -1084,23 +1094,6 @@ mod tests {
dir
}
- fn wait_for_note(ndb: &Ndb, note_id: &[u8; 32]) {
- let deadline = Instant::now() + Duration::from_millis(500);
- loop {
- if let Ok(txn) = Transaction::new(ndb) {
- if ndb.get_note_by_id(&txn, note_id).is_ok() {
- return;
- }
- }
-
- if Instant::now() >= deadline {
- panic!("timed out waiting for note ingestion");
- }
-
- std::thread::sleep(Duration::from_millis(10));
- }
- }
-
#[test]
fn build_address_filter_includes_only_d_tags() {
let author = [1u8; 32];
@@ -1128,8 +1121,8 @@ mod tests {
assert!(saw_d_tag, "expected filter to include a 'd' tag constraint");
}
- #[test]
- fn query_note_by_address_uses_d_and_a_tag_filters() {
+ #[tokio::test]
+ async fn query_note_by_address_uses_d_and_a_tag_filters() {
let keys = Keys::generate();
let author = keys.public_key().to_bytes();
let kind = Kind::LongFormTextNote.as_u16() as u64;
@@ -1153,15 +1146,22 @@ mod tests {
.sign_with_keys(&keys)
.expect("sign long-form event with coordinate tag");
+ let event_with_d_id = event_with_d.id.to_bytes();
+ let event_with_a_only_id = event_with_a_only.id.to_bytes();
ndb.process_event(&serde_json::to_string(&event_with_d).unwrap())
.expect("ingest event with d tag");
ndb.process_event(&serde_json::to_string(&event_with_a_only).unwrap())
.expect("ingest event with a tag");
- let event_with_d_id = event_with_d.id.to_bytes();
- let event_with_a_only_id = event_with_a_only.id.to_bytes();
- wait_for_note(&ndb, &event_with_d_id);
- wait_for_note(&ndb, &event_with_a_only_id);
+ let wait_filter = Filter::new().ids([&event_with_d_id]).build();
+ let wait_filter_2 = Filter::new().ids([&event_with_a_only_id]).build();
+ let subscription = ndb
+ .subscribe(&[wait_filter, wait_filter_2])
+ .expect("subscribe to ingestion markers");
+ let _ = ndb
+ .wait_for_notes(subscription, 2)
+ .await
+ .expect("wait for note ingestion to complete");
{
let txn = Transaction::new(&ndb).expect("transaction for d-tag lookup");