diff --git a/apps/cory/ssblit.json b/apps/cory/ssblit.json index 3f800199..58006a15 100644 --- a/apps/cory/ssblit.json +++ b/apps/cory/ssblit.json @@ -1 +1 @@ -{"type":"tildefriends-app","files":{"app.js":"&viCT+Sz8weP/j5V47w0wA4sk46HM4uy6lajX5NtoqHE=.sha256","lit-all.min.js":"&N4A12AsifdQgwdpII0SFtG513BfoLpmPjdJ9VTDftpg=.sha256","index.html":"&WH8A5tF25xlfPDGei2TCQc2/HJFJf5DuRN1GRSYQhhk=.sha256","script.js":"&G8puK9Q4MngHy3D4ppcKyT49WKbHD2OCeUcAw2ghTDE=.sha256","lit-all.min.js.map":"&oFY9wO4MnujgfGNGv4VggHc5V5JwX4C8csqKZ6KJYbE=.sha256","tf-id-picker.js":"&pg1gLK150HFai73TcmAe5E/dMpMqmbhyre/+/J4XmHo=.sha256","tf-app.js":"&Zt1x1urnzk0D9TxQvgJqOjdHelW+bei7CRupODgvAsk=.sha256","tf-message.js":"&KE1fWTqPMZR0yIRXPBGy8u1chR6LTguSK6swo+lFgE4=.sha256","tf-user.js":"&L6+7BnBq+UOoTMO6o8+u5JFTl0UBtCPDw8bb8ppDrkA=.sha256","tf-utils.js":"&N2yKZwFnb2GbPeipgQtu6xFvezENNOgud9G7EhCQ/K0=.sha256","commonmark.min.js":"&bfBaMLU19d1p/vPBF9hlARqDX002KXG/UOfxOahZhe4=.sha256","tf-compose.js":"&oo0iWvT+c2rU91zWpBIfPePRzmU8qmSnVOm+QCQqG/I=.sha256","emojis.json":"&h3P4pez+AI4aYdsN0dJ3pbUEFR0276t9AM20caj/W/s=.sha256","emojis.js":"&htPMi2z6Bmgi3f9jCnECCDZRCHACnDRjOl1kgPm+W80=.sha256","tf-styles.js":"&BkvFkMpGyL0DYP6FISFKR4pe6ZBOp8t6tQEzWZ4IQYs=.sha256","tf-profile.js":"&vRKjsnYvOiHCQahzEfznCvP5YDwUPtltlpWf+pxwZ1Y=.sha256","commonmark-linkify.js":"&X+hNNkmSRvKY86khyAun+cXksquXbMakZdINbGbx30g=.sha256","tf-tab-search.js":"&Q4bstnLzTPmCKJP+cf7FfRZJVuGAltEely4oIovUVaI=.sha256","tf-tab-news.js":"&Pc/FkHOPRPyWZi/znjquVtXeykzqqFygVuNm0dxrwlI=.sha256","tf-tab-connections.js":"&jSnF/5NmgqxRze1XQAEGOW5mPzOV1/8aCyrDRZu34IQ=.sha256","tf-news.js":"&C1dKe98kQOkClnAbGvcreC15IdlTrD9J4RFohspnsSE=.sha256"}} \ No newline at end of file +{"type":"tildefriends-app","files":{"app.js":"&viCT+Sz8weP/j5V47w0wA4sk46HM4uy6lajX5NtoqHE=.sha256","lit-all.min.js":"&N4A12AsifdQgwdpII0SFtG513BfoLpmPjdJ9VTDftpg=.sha256","index.html":"&WH8A5tF25xlfPDGei2TCQc2/HJFJf5DuRN1GRSYQhhk=.sha256","script.js":"&G8puK9Q4MngHy3D4ppcKyT49WKbHD2OCeUcAw2ghTDE=.sha256","lit-all.min.js.map":"&oFY9wO4MnujgfGNGv4VggHc5V5JwX4C8csqKZ6KJYbE=.sha256","tf-id-picker.js":"&pg1gLK150HFai73TcmAe5E/dMpMqmbhyre/+/J4XmHo=.sha256","tf-app.js":"&F64EHiKTMf/65Cc0w/F7oFbBcUOn7uTAjFBPd5rymSs=.sha256","tf-message.js":"&AFDKCN+hxYDs7zG8PBKmle11gE/2AIMzYr3FYz1hCto=.sha256","tf-user.js":"&L6+7BnBq+UOoTMO6o8+u5JFTl0UBtCPDw8bb8ppDrkA=.sha256","tf-utils.js":"&N2yKZwFnb2GbPeipgQtu6xFvezENNOgud9G7EhCQ/K0=.sha256","commonmark.min.js":"&bfBaMLU19d1p/vPBF9hlARqDX002KXG/UOfxOahZhe4=.sha256","tf-compose.js":"&oo0iWvT+c2rU91zWpBIfPePRzmU8qmSnVOm+QCQqG/I=.sha256","emojis.json":"&h3P4pez+AI4aYdsN0dJ3pbUEFR0276t9AM20caj/W/s=.sha256","emojis.js":"&pqYLDE/13PyEt2ceeFqvnwZ8NqWfPfpDBt4vP8SeHbs=.sha256","tf-styles.js":"&Ab+SjsySJ74kwK3EQD/j72yXYJlFAhkJ5EqyJfYpJEk=.sha256","tf-profile.js":"&vRKjsnYvOiHCQahzEfznCvP5YDwUPtltlpWf+pxwZ1Y=.sha256","commonmark-linkify.js":"&X+hNNkmSRvKY86khyAun+cXksquXbMakZdINbGbx30g=.sha256","tf-tab-search.js":"&NUGpMnLR3eYwrdjZaJAd8s4Rj+WPazJhWWX5jkMdNRI=.sha256","tf-tab-news.js":"&ehXkzOR+kQmiTHRtu5GPDMwrB4a4Z9vVsTo4ldhdu/E=.sha256","tf-tab-connections.js":"&jSnF/5NmgqxRze1XQAEGOW5mPzOV1/8aCyrDRZu34IQ=.sha256","tf-news.js":"&C1dKe98kQOkClnAbGvcreC15IdlTrD9J4RFohspnsSE=.sha256"}} \ No newline at end of file diff --git a/apps/cory/ssblit/emojis.js b/apps/cory/ssblit/emojis.js index 187e295e..7b61f7ea 100644 --- a/apps/cory/ssblit/emojis.js +++ b/apps/cory/ssblit/emojis.js @@ -38,7 +38,6 @@ export function picker(callback, anchor) { list.removeChild(list.firstChild); } let search = input.value; - console.log('refresh', search); Object.entries(json).forEach(function(row) { let header = document.createElement('div'); header.appendChild(document.createTextNode(row[0])); diff --git a/apps/cory/ssblit/tf-app.js b/apps/cory/ssblit/tf-app.js index a3b2e7c8..d85a34ee 100644 --- a/apps/cory/ssblit/tf-app.js +++ b/apps/cory/ssblit/tf-app.js @@ -11,6 +11,10 @@ class TfElement extends LitElement { tab: {type: String}, broadcasts: {type: Array}, connections: {type: Array}, + loading: {type: Boolean}, + loaded: {type: Boolean}, + following: {type: Array}, + users: {type: Object}, }; } @@ -24,6 +28,9 @@ class TfElement extends LitElement { this.tab = 'news'; this.broadcasts = []; this.connections = []; + this.following = []; + this.users = {}; + this.loaded = false; tfrpc.rpc.getBroadcasts().then(b => { self.broadcasts = b || [] }); tfrpc.rpc.getConnections().then(c => { self.connections = c || [] }); tfrpc.rpc.getHash().then(hash => self.hash = hash || '#'); @@ -40,9 +47,7 @@ class TfElement extends LitElement { self.connections = value; } }); - tfrpc.rpc.localStorageGet('whoami').then(function(value) { - self.whoami = value; - }); + tfrpc.rpc.localStorageGet('whoami').then(whoami => self.whoami = whoami); } async contacts_internal(id, last_row_id, following, max_row_id) { @@ -71,31 +76,29 @@ class TfElement extends LitElement { delete result.blocking[contact.contact]; } } + following[id] = result; return result; } - async contact(id, last_row_id, following, max_row_id, contact_cache) { - let result = await this.contacts_internal(id, last_row_id, following, max_row_id); - contact_cache[id] = Object.assign(contact_cache[id] || {}, result); - following[id] = contact_cache[id]; - return result; + async contact(id, last_row_id, following, max_row_id) { + return await this.contacts_internal(id, last_row_id, following, max_row_id); } - async following_deep_internal(ids, depth, blocking, last_row_id, following, max_row_id, contact_cache) { - let contacts = await Promise.all([...new Set(ids)].map(x => this.contact(x, last_row_id, following, max_row_id, contact_cache))); + async following_deep_internal(ids, depth, blocking, last_row_id, following, max_row_id) { + let contacts = await Promise.all([...new Set(ids)].map(x => this.contact(x, last_row_id, following, max_row_id))); let result = {}; for (let i = 0; i < ids.length; i++) { let id = ids[i]; let contact = contacts[i]; let found = Object.keys(contact.following).filter(y => !contact.blocking[y]); - let deeper = depth > 1 ? await this.following_deep_internal(found, depth - 1, Object.assign({}, contact.blocking, blocking), last_row_id, following, max_row_id, contact_cache) : []; + let deeper = depth > 1 ? await this.following_deep_internal(found, depth - 1, Object.assign({}, contact.blocking, blocking), last_row_id, following, max_row_id) : []; result[id] = [id, ...found, ...deeper]; } return [...new Set(Object.values(result).flat())]; } async following_deep(ids, depth, blocking) { - const k_cache_version = 4; + const k_cache_version = 5; let cache = await tfrpc.rpc.databaseGet('following'); cache = cache ? JSON.parse(cache) : {}; if (cache.version !== k_cache_version) { @@ -105,14 +108,14 @@ class TfElement extends LitElement { last_row_id: 0, }; } - let contact_cache = {}; let max_row_id = (await tfrpc.rpc.query(` SELECT MAX(rowid) AS max_row_id FROM messages `, []))[0].max_row_id; - let result = await this.following_deep_internal(ids, depth, blocking, cache.last_row_id, cache.following, max_row_id, contact_cache); + let result = await this.following_deep_internal(ids, depth, blocking, cache.last_row_id, cache.following, max_row_id); cache.last_row_id = max_row_id; await tfrpc.rpc.databaseSet('following', JSON.stringify(cache)); - return result; + console.log(cache); + return [result, cache.following]; } async fetch_about(ids, users) { @@ -191,24 +194,16 @@ class TfElement extends LitElement { WHERE messages.id = ? `, [ - JSON.stringify(this.allFollowing), + JSON.stringify(this.following), id, ]); - let self = this; - let mine = messages.filter(m => m.author === self.whoami); - if (mine.length) { - this.process_messages(mine); - await this.finalize_messages(); - } - let other = messages.filter(m => m.author !== self.whoami); - if (other.length) { - this.unread = [...this.unread, ...other]; + if (messages && messages.length) { + this.unread = [...this.unread, ...messages]; } } _handle_whoami_changed(event) { if (this.whoami !== event.srcElement.selected) { - console.log('whoami changed', event.srcElement.selected); this.whoami = event.srcElement.selected; } } @@ -228,26 +223,58 @@ class TfElement extends LitElement { `; } - async render_tab() { - let following = await this.following_deep([this.whoami], 2, {}); - let users = await this.fetch_about(following.sort()); + async load() { + let whoami = this.whoami; + let [following, users] = await this.following_deep([whoami], 2, {}); + users = await this.fetch_about(following.sort(), users); + this.following = following; + this.users = users; + this.whoami = whoami; + this.loaded = whoami; + } + + render_tab() { + let following = this.following; + let users = this.users; if (this.tab === 'news') { return html` - this.unread = []}> + this.unread = []}> `; } else if (this.tab === 'connections') { return html` - + `; } else if (this.tab === 'search') { return html` - + `; } } + add_fake_news() { + this.unread = [{ + author: this.whoami, + placeholder: true, + id: '%fake_id', + text: 'text', + content: 'hello', + }, ...this.unread]; + } + render() { let self = this; + + if (!this.loading && this.whoami && this.loaded !== this.whoami) { + console.log('loading', this.whoami); + this.loading = true; + this.following = []; + this.users = {}; + this.load().finally(function() { + self.loading = false; + console.log('loaded'); + }); + } + let id_picker = html` ${guard([this.whoami], () => until(this.render_id_picker(), html`
Loading...
`))} `; @@ -258,10 +285,14 @@ class TfElement extends LitElement { self.tab = 'search'}> `; + let contents = !this.loaded ? + html`
Loading...
` : + this.render_tab(); return html` ${id_picker} ${tabs} - ${until(this.render_tab(), html`
Loading...
`)} + + ${contents} `; } } diff --git a/apps/cory/ssblit/tf-message.js b/apps/cory/ssblit/tf-message.js index a02bca27..aebf7fbd 100644 --- a/apps/cory/ssblit/tf-message.js +++ b/apps/cory/ssblit/tf-message.js @@ -73,6 +73,40 @@ class TfMessageElement extends LitElement { emojis.picker(x => this.vote(x)); } + render_mention(mention) { + if (mention.link?.startsWith('&') && + mention.type?.startsWith('image/')) { + return html` + + `; + } else if (mention.link?.startsWith('&') && + mention.name?.startsWith('audio:')) { + return html` + + `; + } else if (mention.link?.startsWith('%') || mention.link?.startsWith('@')) { + return html` ${mention.name}`; + } else if (mention.link?.startsWith('#')) { + return html` ${mention.link}`; + } else { + return html`
${JSON.stringify(mention)}
`; + } + } + + render_mentions() { + if (this.message?.content?.mentions?.length) { + let self = this; + return html` +
+ Mentions + ${(this.message?.content?.mentions || []).map(x => self.render_mention(x))} +
+ `; + } + } + render() { let content = this.message?.content; let self = this; @@ -153,6 +187,7 @@ class TfMessageElement extends LitElement { ${raw_button}
${body}
+ ${this.render_mentions()} ${this.render_votes()}
${reply} diff --git a/apps/cory/ssblit/tf-styles.js b/apps/cory/ssblit/tf-styles.js index 5ff39ddb..4de19f50 100644 --- a/apps/cory/ssblit/tf-styles.js +++ b/apps/cory/ssblit/tf-styles.js @@ -12,4 +12,9 @@ a:visited { a:hover { color: #ddf; } + +img { + max-width: 640px; + max-height: 480px; +} `; \ No newline at end of file diff --git a/apps/cory/ssblit/tf-tab-news.js b/apps/cory/ssblit/tf-tab-news.js index 4e52fbf5..08138886 100644 --- a/apps/cory/ssblit/tf-tab-news.js +++ b/apps/cory/ssblit/tf-tab-news.js @@ -2,14 +2,14 @@ import {LitElement, html, unsafeHTML, until} from './lit-all.min.js'; import * as tfrpc from '/static/tfrpc.js'; import {styles} from './tf-styles.js'; -class TfTabNewsElement extends LitElement { +class TfTabNewsFeedElement extends LitElement { static get properties() { return { whoami: {type: String}, users: {type: Object}, hash: {type: String}, - unread: {type: Array}, following: {type: Array}, + messages: {type: Array}, } } @@ -21,9 +21,7 @@ class TfTabNewsElement extends LitElement { this.whoami = null; this.users = {}; this.hash = '#'; - this.unread = []; this.following = []; - this.cache = {}; } async fetch_messages() { @@ -65,42 +63,86 @@ class TfTabNewsElement extends LitElement { } } - async show_more() { - let unread = this.unread; - this.unread = []; - this.process_messages(unread); - await this.finalize_messages(); + render() { + if (!this.messages || + this._messages_hash !== this.hash || + this._messages_following !== this.following) { + console.log('loading messages'); + let self = this; + this.messages = []; + this._messages_hash = this.hash; + this._messages_following = this.following; + this.fetch_messages().then(function(messages) { + self.messages = messages; + }); + } + return html``; + } +} + +class TfTabNewsElement extends LitElement { + static get properties() { + return { + whoami: {type: String}, + users: {type: Object}, + hash: {type: String}, + unread: {type: Array}, + following: {type: Array}, + } } - async render_news() { - if (this.cache.hash !== this.hash || - this.cache.whoami !== this.whoami || - this.cache.users !== this.users || - !this.cache.messages) { - this.cache = { - hash: this.hash, - whoami: this.whoami, - users: this.users, - messages: this.fetch_messages(), - }; + static styles = styles; + + constructor() { + super(); + let self = this; + this.whoami = null; + this.users = {}; + this.hash = '#'; + this.unread = []; + this.following = []; + this.cache = {}; + } + + show_more() { + let unread = this.unread; + let news = this.renderRoot?.getElementById('news'); + if (news) { + console.log('injecting messages', news.messages); + news.messages = [...this.unread, ...news.messages]; + this.dispatchEvent(new CustomEvent('refresh')); } - let messages = await this.cache.messages; - return html``; + } + + new_messages_text() { + if (!this.unread?.length) { + return 'No new messages.'; + } + let counts = {}; + for (let message of this.unread) { + let type = 'unknown'; + try { + type = JSON.parse(message.content).type || type; + } catch { + } + counts[type] = (counts[type] || 0) + 1; + } + return 'Show New: ' + Object.keys(counts).sort().map(x => (counts[x].toString() + ' ' + x + 's')).join(', '); } render() { let profile = this.hash.startsWith('#@') ? html`` : undefined; return html` -
- +
🏠Home
Welcome, !
${profile} - ${until(this.render_news(), html`
Loading...
`)} + `; } } +customElements.define('tf-tab-news-feed', TfTabNewsFeedElement); customElements.define('tf-tab-news', TfTabNewsElement); \ No newline at end of file diff --git a/apps/cory/ssblit/tf-tab-search.js b/apps/cory/ssblit/tf-tab-search.js index 83361d96..2d7abfc4 100644 --- a/apps/cory/ssblit/tf-tab-search.js +++ b/apps/cory/ssblit/tf-tab-search.js @@ -31,7 +31,7 @@ class TfTabSearchElement extends LitElement { JOIN json_each(?) AS following ON messages.author = following.value ORDER BY timestamp DESC limit 100 `, - [query, JSON.stringify(this.following)]); + ['"' + query.replace('"', '""') + '"', JSON.stringify(this.following)]); console.log('Done.'); this.renderRoot.getElementById('search').value = ''; this.renderRoot.getElementById('news').messages = results;