diff --git a/src/apps/web/WebData.h b/src/apps/web/WebData.h index d5aa984..2275837 100644 --- a/src/apps/web/WebData.h +++ b/src/apps/web/WebData.h @@ -595,11 +595,14 @@ struct UserEvents { }; std::vector eventClusterArr; + uint64_t totalEvents = 0; + std::optional timestampCutoff; + std::optional nextResumeTime; - UserEvents(lmdb::txn &txn, Decompressor &decomp, const std::string &pubkey) : u(txn, decomp, pubkey) { + UserEvents(lmdb::txn &txn, Decompressor &decomp, const std::string &pubkey, uint64_t resumeTime) : u(txn, decomp, pubkey) { flat_hash_map eventClusters; // eventId (root) -> EventCluster - env.generic_foreachFull(txn, env.dbi_Event__pubkeyKind, makeKey_StringUint64Uint64(pubkey, 1, MAX_U64), "", [&](std::string_view k, std::string_view v){ + env.generic_foreachFull(txn, env.dbi_Event__pubkeyKind, makeKey_StringUint64Uint64(pubkey, 1, resumeTime), "", [&](std::string_view k, std::string_view v){ ParsedKey_StringUint64Uint64 parsedKey(k); if (parsedKey.s != pubkey || parsedKey.n1 != 1) return false; @@ -617,6 +620,7 @@ struct UserEvents { cluster.isRootEventFromUser = rootEvent.getPubkey() == u.pubkey; cluster.rootEventTimestamp = rootEvent.getCreatedAt(); cluster.eventCache.emplace(rootId, std::move(rootEvent)); + totalEvents++; }; if (ev.root.size()) { @@ -635,6 +639,7 @@ struct UserEvents { } eventClusters.at(ev.root).eventCache.emplace(id, std::move(ev)); + totalEvents++; } else { // Event is root @@ -643,6 +648,15 @@ struct UserEvents { } } + if (timestampCutoff) { + if (*timestampCutoff != parsedKey.n2) { + nextResumeTime = *timestampCutoff - 1; + return false; + } + } else if (totalEvents > 100) { + timestampCutoff = parsedKey.n2; + } + return true; }, true); @@ -666,9 +680,11 @@ struct UserEvents { struct { std::vector &renderedThreads; User &u; + std::optional nextResumeTime; } ctx = { renderedThreads, u, + nextResumeTime, }; return tmpl::user::comments(ctx); diff --git a/src/apps/web/WebReader.cpp b/src/apps/web/WebReader.cpp index 02a2179..525d8b4 100644 --- a/src/apps/web/WebReader.cpp +++ b/src/apps/web/WebReader.cpp @@ -217,7 +217,14 @@ HTTPResponse WebServer::generateReadResponse(lmdb::txn &txn, Decompressor &decom } if (u.path[2] == "notes") { - UserEvents uc(txn, decomp, userPubkey); + uint64_t resumeTime = MAX_U64; + + try { + auto resumeTimeStr = u.lookupQuery("next"); + if (resumeTimeStr) resumeTime = std::stoull(std::string(*resumeTimeStr)); + } catch(...) {} + + UserEvents uc(txn, decomp, userPubkey, resumeTime); title = std::string("notes: ") + uc.u.username; body = uc.render(txn, decomp); } else if (u.path[2] == "export.jsonl") { diff --git a/src/apps/web/WebUtils.h b/src/apps/web/WebUtils.h index 1eb4439..bcde7ee 100644 --- a/src/apps/web/WebUtils.h +++ b/src/apps/web/WebUtils.h @@ -22,6 +22,34 @@ struct Url { if (u.size()) path.emplace_back(u); } + + std::optional lookupQuery(std::string_view key) { + std::string_view curr = query; + + while (curr.size()) { + auto nextPos = curr.find("&"); + + { + std::string_view currKV = nextPos == std::string::npos ? curr : curr.substr(0, nextPos); + std::string_view k, v; + + auto equalsPos = currKV.find("="); + if (equalsPos == std::string::npos) { + k = currKV; + } else { + k = currKV.substr(0, equalsPos); + v = currKV.substr(equalsPos + 1); + } + + if (k == key) return v; + } + + if (nextPos == std::string::npos) break; + curr = curr.substr(nextPos + 1); + } + + return std::nullopt; + } }; inline std::string renderTimestamp(uint64_t now, uint64_t ts) { diff --git a/src/apps/web/static/oddbean.css b/src/apps/web/static/oddbean.css index 5ff3219..415a2f0 100644 --- a/src/apps/web/static/oddbean.css +++ b/src/apps/web/static/oddbean.css @@ -180,9 +180,16 @@ table.vert { /* user comments */ -.user-comments > div { - margin-bottom: 30px; - border-bottom: 1px solid black; +.user-comments { + .note-thread { + margin-bottom: 30px; + border-bottom: 1px solid black; + } + + .more-notes { + margin-left: 20px; + margin-bottom: 20px; + } } diff --git a/src/apps/web/tmpls/user/comments.tmpl b/src/apps/web/tmpls/user/comments.tmpl index fb0b3be..1f12949 100644 --- a/src/apps/web/tmpls/user/comments.tmpl +++ b/src/apps/web/tmpls/user/comments.tmpl @@ -1,10 +1,14 @@
-

+

Notes by $(ctx.u.username) | export

-
@(auto &r : ctx.renderedThreads) +
@(auto &r : ctx.renderedThreads) $(r)
+ +
?(ctx.nextResumeTime) + More notes by $(ctx.u.username) +