From 09c7eb8318d096aa31786101c4ede959c537aacd Mon Sep 17 00:00:00 2001 From: Iris Lightshard Date: Sat, 31 Aug 2024 11:01:31 -0600 Subject: [PATCH] start implementing boost carousel --- adapter/misskey.go | 1 + frontend/ts/adapter-element.ts | 22 ++++++++++++++++++---- frontend/ts/boost-tile-element.ts | 14 ++++++++++++++ frontend/ts/message.ts | 1 + frontend/ts/websocket.ts | 5 ++--- models/msg.go | 1 + 6 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 frontend/ts/boost-tile-element.ts diff --git a/adapter/misskey.go b/adapter/misskey.go index 49e2f9d..cc6140a 100644 --- a/adapter/misskey.go +++ b/adapter/misskey.go @@ -216,6 +216,7 @@ func (self *MisskeyAdapter) toMessage(n mkm.Note, bustCache bool) *Message { ReplyTo: n.ReplyID, ReplyCount: int(n.RepliesCount), Replies: []string{}, + RenoteId: (*string)(n.RenoteID), } for _, f := range n.Files { diff --git a/frontend/ts/adapter-element.ts b/frontend/ts/adapter-element.ts index d8ba09c..92063da 100644 --- a/frontend/ts/adapter-element.ts +++ b/frontend/ts/adapter-element.ts @@ -24,6 +24,7 @@ export class AdapterElement extends HTMLElement { // TODO: use visibility of the thread to organize into DMs and public threads private _threads: MessageThread[] = []; private _orphans: Message[] = []; + private _boosts: Message[] = []; constructor() { super(); @@ -102,6 +103,7 @@ export class AdapterElement extends HTMLElement { tse.setAttribute("data-author", this._latest); } } + // also update any boosts by this author case "thread": case "profile": break; @@ -113,7 +115,7 @@ export class AdapterElement extends HTMLElement { } setIdxView() { - this.innerHTML = "" + this.innerHTML = "" } setThreadView() { @@ -132,6 +134,8 @@ export class AdapterElement extends HTMLElement { } populateIdxView() { + // populate boost carousel + // skip dm list for now // public/unified list const pl = util.$("public_list"); @@ -149,11 +153,12 @@ export class AdapterElement extends HTMLElement { const existingThread = document.querySelector(threadSelector); const thread = this._threads.find(t=>t.root.data.id == rootId); if (existingThread && thread) { - debugger; existingThread.setAttribute("data-latest", `${thread.latest}`); existingThread.setAttribute("data-len", `${thread.messageCount}`); existingThread.setAttribute("data-new", "true"); } else { + // if latest is a boost, put it in the carousel + // unified/public list for now const pl = util.$("public_list"); if (pl && thread) { @@ -190,14 +195,14 @@ export class AdapterElement extends HTMLElement { return; } // make multiple passes over the store until every message is either - // placed in a thread, or orphaned and waiting for its parent to be returned + // placed in a thread, the boost carousel, or orphaned and waiting for its parent to be returned do{ for (let k of datastore.messages.keys()) { this.placeMsg(k); } } while (this._threads.reduce((sum: number, thread: MessageThread)=>{ return sum + thread.messageCount; - }, 0) + this._orphans.length < datastore.messages.size); + }, 0) + this._boosts.length + this._orphans.length < datastore.messages.size); } placeMsg(k: string): string | null { @@ -211,11 +216,20 @@ export class AdapterElement extends HTMLElement { util.errMsg(`message [${this._name}:${k}] doesn't exist`); return null; } + if (msg.renoteId) { + // fetch the referent thread and put the boost in the carousel + this._convoyBatchTimer.queue(msg.renoteId, 2000); + if (!this._boosts.some(m=>m.id == msg.id)) { + this._boosts.push(msg); + } + return null; + } for (let t of this._threads) { // avoid processing nodes again on subsequent passes if (!msg || t.findNode(t.root, msg.id)) { return null; } + if (msg.replyTo) { let x = t.addReply(msg.replyTo, msg); if (x) { diff --git a/frontend/ts/boost-tile-element.ts b/frontend/ts/boost-tile-element.ts new file mode 100644 index 0000000..8fe0da1 --- /dev/null +++ b/frontend/ts/boost-tile-element.ts @@ -0,0 +1,14 @@ +export class BoostTileElement extends HTMLElement { + + static observedAttributes = [ "data-boostid", "data-msgid", "data-author", "data-booster" ]; + + constructor() { + this.innerHTML = "
"; + } + + connectedCallback() { + } + + attributeChangedCallback(attr: string, prev: string, next: string) { + } +} \ No newline at end of file diff --git a/frontend/ts/message.ts b/frontend/ts/message.ts index e7dc2f0..70d31eb 100644 --- a/frontend/ts/message.ts +++ b/frontend/ts/message.ts @@ -12,6 +12,7 @@ export class Message { public created: number = 0; public edited: number | null = null; public visibility: string = "public"; + public renoteId: string | null = null; } export class Author { diff --git a/frontend/ts/websocket.ts b/frontend/ts/websocket.ts index f510aa3..ef01f2b 100644 --- a/frontend/ts/websocket.ts +++ b/frontend/ts/websocket.ts @@ -58,13 +58,12 @@ export class DatagramSocket { } static connect(): void { - - - const wsProto = location.protocol == "https:" ? "wss" : "ws"; const _conn = new WebSocket(`${wsProto}://${location.host}/subscribe`, "underbbs"); + _conn.addEventListener("open", DatagramSocket.onOpen); _conn.addEventListener("message", DatagramSocket.onMsg); + _conn.addEventListener("error", (e: any) => { console.log("websocket connection error"); console.log(JSON.stringify(e)); diff --git a/models/msg.go b/models/msg.go index 7c7c666..270be57 100644 --- a/models/msg.go +++ b/models/msg.go @@ -25,6 +25,7 @@ type Message struct { ReplyCount int `json:"replyCount"` Mentions []string `json:"mentions"` Visibility string `json:"visibility"` + RenoteId *string `json:"renoteId,omitempty"` } type Author struct {