| 
									
										
										
										
											2025-01-27 21:02:15 -05:00
										 |  |  |  | import { | 
					
						
							|  |  |  |  | 	LitElement, | 
					
						
							|  |  |  |  | 	cache, | 
					
						
							|  |  |  |  | 	keyed, | 
					
						
							|  |  |  |  | 	html, | 
					
						
							|  |  |  |  | 	unsafeHTML, | 
					
						
							|  |  |  |  | 	until, | 
					
						
							|  |  |  |  | } from './lit-all.min.js'; | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  |  | import * as tfrpc from '/static/tfrpc.js'; | 
					
						
							| 
									
										
										
										
											2025-10-22 19:39:20 -04:00
										 |  |  |  | import {styles, generate_theme} from './tf-styles.js'; | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-14 23:33:57 +00:00
										 |  |  |  | class TfTabNewsElement extends LitElement { | 
					
						
							|  |  |  |  | 	static get properties() { | 
					
						
							|  |  |  |  | 		return { | 
					
						
							|  |  |  |  | 			whoami: {type: String}, | 
					
						
							|  |  |  |  | 			users: {type: Object}, | 
					
						
							|  |  |  |  | 			hash: {type: String}, | 
					
						
							|  |  |  |  | 			following: {type: Array}, | 
					
						
							| 
									
										
										
										
											2023-01-21 00:16:18 +00:00
										 |  |  |  | 			drafts: {type: Object}, | 
					
						
							| 
									
										
										
										
											2023-01-25 00:56:10 +00:00
										 |  |  |  | 			expanded: {type: Object}, | 
					
						
							| 
									
										
										
										
											2024-05-11 10:40:34 -04:00
										 |  |  |  | 			loading: {type: Boolean}, | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  |  | 			channels: {type: Array}, | 
					
						
							|  |  |  |  | 			channels_unread: {type: Object}, | 
					
						
							|  |  |  |  | 			channels_latest: {type: Object}, | 
					
						
							| 
									
										
										
										
											2024-12-29 14:54:29 -05:00
										 |  |  |  | 			connections: {type: Array}, | 
					
						
							| 
									
										
										
										
											2025-02-05 18:41:37 -05:00
										 |  |  |  | 			private_messages: {type: Array}, | 
					
						
							| 
									
										
										
										
											2025-08-13 19:16:34 -04:00
										 |  |  |  | 			grouped_private_messages: {type: Object}, | 
					
						
							| 
									
										
										
										
											2025-10-26 12:46:06 -04:00
										 |  |  |  | 			visible_private_messages: {type: Object}, | 
					
						
							| 
									
										
										
										
											2025-04-29 20:48:47 -04:00
										 |  |  |  | 			recent_reactions: {type: Array}, | 
					
						
							| 
									
										
										
										
											2025-06-11 20:53:51 -04:00
										 |  |  |  | 			peer_exchange: {type: Boolean}, | 
					
						
							| 
									
										
										
										
											2025-07-02 12:41:03 -04:00
										 |  |  |  | 			is_administrator: {type: Boolean}, | 
					
						
							|  |  |  |  | 			stay_connected: {type: Boolean}, | 
					
						
							| 
									
										
										
										
											2023-03-29 22:02:12 +00:00
										 |  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2022-09-14 23:33:57 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	static styles = styles; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	constructor() { | 
					
						
							|  |  |  |  | 		super(); | 
					
						
							|  |  |  |  | 		let self = this; | 
					
						
							|  |  |  |  | 		this.whoami = null; | 
					
						
							|  |  |  |  | 		this.users = {}; | 
					
						
							|  |  |  |  | 		this.hash = '#'; | 
					
						
							|  |  |  |  | 		this.following = []; | 
					
						
							|  |  |  |  | 		this.cache = {}; | 
					
						
							| 
									
										
										
										
											2023-01-21 00:16:18 +00:00
										 |  |  |  | 		this.drafts = {}; | 
					
						
							| 
									
										
										
										
											2023-01-25 00:56:10 +00:00
										 |  |  |  | 		this.expanded = {}; | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  |  | 		this.channels_unread = {}; | 
					
						
							|  |  |  |  | 		this.channels_latest = {}; | 
					
						
							|  |  |  |  | 		this.channels = []; | 
					
						
							| 
									
										
										
										
											2024-12-29 14:54:29 -05:00
										 |  |  |  | 		this.connections = []; | 
					
						
							| 
									
										
										
										
											2025-04-29 20:48:47 -04:00
										 |  |  |  | 		this.recent_reactions = []; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  |  | 		tfrpc.rpc.localStorageGet('drafts').then(function (d) { | 
					
						
							| 
									
										
										
										
											2023-01-21 00:16:18 +00:00
										 |  |  |  | 			self.drafts = JSON.parse(d || '{}'); | 
					
						
							|  |  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2025-06-14 20:27:19 -04:00
										 |  |  |  | 		this.check_peer_exchange(); | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-02 16:47:27 +00:00
										 |  |  |  | 	connectedCallback() { | 
					
						
							|  |  |  |  | 		super.connectedCallback(); | 
					
						
							|  |  |  |  | 		document.body.addEventListener('keypress', this.on_keypress.bind(this)); | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	disconnectedCallback() { | 
					
						
							|  |  |  |  | 		super.disconnectedCallback(); | 
					
						
							|  |  |  |  | 		document.body.removeEventListener('keypress', this.on_keypress.bind(this)); | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-14 20:27:19 -04:00
										 |  |  |  | 	async check_peer_exchange() { | 
					
						
							|  |  |  |  | 		if (await tfrpc.rpc.isAdministrator()) { | 
					
						
							|  |  |  |  | 			this.peer_exchange = await tfrpc.rpc.globalSettingsGet('peer_exchange'); | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							|  |  |  |  | 			this.peer_exchange = undefined; | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-29 13:32:37 -05:00
										 |  |  |  | 	load_latest() { | 
					
						
							| 
									
										
										
										
											2023-05-03 22:32:21 +00:00
										 |  |  |  | 		let news = this.shadowRoot?.getElementById('news'); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:33:57 +00:00
										 |  |  |  | 		if (news) { | 
					
						
							| 
									
										
										
										
											2024-12-01 18:20:57 -05:00
										 |  |  |  | 			news.load_latest(); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:33:57 +00:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-21 00:16:18 +00:00
										 |  |  |  | 	draft(event) { | 
					
						
							|  |  |  |  | 		let id = event.detail.id || ''; | 
					
						
							| 
									
										
										
										
											2023-01-28 19:39:41 +00:00
										 |  |  |  | 		let previous = this.drafts[id]; | 
					
						
							| 
									
										
										
										
											2023-01-21 00:16:18 +00:00
										 |  |  |  | 		if (event.detail.draft !== undefined) { | 
					
						
							| 
									
										
										
										
											2023-01-28 19:39:41 +00:00
										 |  |  |  | 			this.drafts[id] = event.detail.draft; | 
					
						
							| 
									
										
										
										
											2023-01-21 00:16:18 +00:00
										 |  |  |  | 		} else { | 
					
						
							|  |  |  |  | 			delete this.drafts[id]; | 
					
						
							| 
									
										
										
										
											2023-01-28 19:39:41 +00:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-04-24 20:19:14 -04:00
										 |  |  |  | 		this.drafts = Object.assign({}, this.drafts); | 
					
						
							| 
									
										
										
										
											2023-01-21 00:16:18 +00:00
										 |  |  |  | 		tfrpc.rpc.localStorageSet('drafts', JSON.stringify(this.drafts)); | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-25 00:56:10 +00:00
										 |  |  |  | 	on_expand(event) { | 
					
						
							|  |  |  |  | 		if (event.detail.expanded) { | 
					
						
							|  |  |  |  | 			let expand = {}; | 
					
						
							|  |  |  |  | 			expand[event.detail.id] = true; | 
					
						
							|  |  |  |  | 			this.expanded = Object.assign({}, this.expanded, expand); | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							|  |  |  |  | 			delete this.expanded[event.detail.id]; | 
					
						
							|  |  |  |  | 			this.expanded = Object.assign({}, this.expanded); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-02 16:47:27 +00:00
										 |  |  |  | 	on_keypress(event) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  |  | 		if (event.target === document.body && event.key == '.') { | 
					
						
							| 
									
										
										
										
											2023-05-02 16:47:27 +00:00
										 |  |  |  | 			this.show_more(); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  |  | 	unread_status(channel) { | 
					
						
							| 
									
										
										
										
											2025-05-07 19:59:39 -04:00
										 |  |  |  | 		if (channel === undefined) { | 
					
						
							| 
									
										
										
										
											2025-05-08 12:39:26 -04:00
										 |  |  |  | 			if ( | 
					
						
							|  |  |  |  | 				Object.keys(this.channels_unread).some((x) => this.unread_status(x)) | 
					
						
							|  |  |  |  | 			) { | 
					
						
							| 
									
										
										
										
											2025-05-07 19:59:39 -04:00
										 |  |  |  | 				return '✉️ '; | 
					
						
							|  |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2025-08-14 12:40:58 -04:00
										 |  |  |  | 		} else if (channel?.startsWith('🔐')) { | 
					
						
							|  |  |  |  | 			let key = JSON.stringify(channel.substring('🔐'.length).split(',')); | 
					
						
							|  |  |  |  | 			if (this.grouped_private_messages?.[key]) { | 
					
						
							|  |  |  |  | 				let grouped_latest = Math.max( | 
					
						
							|  |  |  |  | 					...this.grouped_private_messages?.[key]?.map((x) => x.rowid) | 
					
						
							|  |  |  |  | 				); | 
					
						
							|  |  |  |  | 				if ( | 
					
						
							|  |  |  |  | 					this.channels_unread[channel] === undefined || | 
					
						
							|  |  |  |  | 					grouped_latest > this.channels_unread[channel] | 
					
						
							|  |  |  |  | 				) { | 
					
						
							|  |  |  |  | 					return '✉️ '; | 
					
						
							|  |  |  |  | 				} | 
					
						
							|  |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2025-05-07 19:59:39 -04:00
										 |  |  |  | 		} else if ( | 
					
						
							| 
									
										
										
										
											2024-12-05 20:47:02 -05:00
										 |  |  |  | 			this.channels_latest[channel] && | 
					
						
							| 
									
										
										
										
											2024-12-27 13:25:40 -05:00
										 |  |  |  | 			this.channels_latest[channel] > 0 && | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  |  | 			(this.channels_unread[channel] === undefined || | 
					
						
							| 
									
										
										
										
											2024-12-22 13:16:56 -05:00
										 |  |  |  | 				this.channels_unread[channel] <= this.channels_latest[channel]) | 
					
						
							| 
									
										
										
										
											2024-12-05 20:47:02 -05:00
										 |  |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2024-12-29 15:15:28 -05:00
										 |  |  |  | 			return '✉️ '; | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	show_sidebar() { | 
					
						
							|  |  |  |  | 		this.renderRoot.getElementById('sidebar').style.display = 'block'; | 
					
						
							| 
									
										
										
										
											2024-12-03 19:40:08 -05:00
										 |  |  |  | 		this.renderRoot.getElementById('sidebar_overlay').style.display = 'block'; | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	hide_sidebar() { | 
					
						
							|  |  |  |  | 		this.renderRoot.getElementById('sidebar').style.display = 'none'; | 
					
						
							| 
									
										
										
										
											2024-12-03 19:40:08 -05:00
										 |  |  |  | 		this.renderRoot.getElementById('sidebar_overlay').style.display = 'none'; | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	async channel_toggle_subscribed() { | 
					
						
							|  |  |  |  | 		let channel = this.hash.substring(2); | 
					
						
							|  |  |  |  | 		let subscribed = this.channels.indexOf(channel) != -1; | 
					
						
							|  |  |  |  | 		subscribed = !subscribed; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		await tfrpc.rpc.appendMessage(this.whoami, { | 
					
						
							|  |  |  |  | 			type: 'channel', | 
					
						
							|  |  |  |  | 			channel: channel, | 
					
						
							|  |  |  |  | 			subscribed: subscribed, | 
					
						
							|  |  |  |  | 		}); | 
					
						
							|  |  |  |  | 		if (subscribed) { | 
					
						
							|  |  |  |  | 			this.channels = [].concat([channel], this.channels).sort(); | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2024-12-05 20:47:02 -05:00
										 |  |  |  | 			this.channels = this.channels.filter((x) => x != channel); | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	channel() { | 
					
						
							|  |  |  |  | 		return this.hash.startsWith('##') ? this.hash.substring(2) : undefined; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-16 21:01:24 -04:00
										 |  |  |  | 	compare_follows(a, b) { | 
					
						
							|  |  |  |  | 		return b[1].ts > a[1].ts ? 1 : b[1].ts < a[1].ts ? -1 : 0; | 
					
						
							| 
									
										
										
										
											2025-01-12 14:54:09 -05:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	suggested_follows() { | 
					
						
							| 
									
										
										
										
											2025-01-14 20:15:18 -05:00
										 |  |  |  | 		/* | 
					
						
							| 
									
										
										
										
											2025-01-14 21:37:11 -05:00
										 |  |  |  | 		 ** Filter out people who have used future timestamps so that they aren't | 
					
						
							|  |  |  |  | 		 ** pinned at the top. | 
					
						
							|  |  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2025-01-12 14:54:09 -05:00
										 |  |  |  | 		let self = this; | 
					
						
							| 
									
										
										
										
											2025-07-16 21:01:24 -04:00
										 |  |  |  | 		let now = new Date().valueOf(); | 
					
						
							| 
									
										
										
										
											2025-01-14 20:15:18 -05:00
										 |  |  |  | 		return Object.entries(this.users) | 
					
						
							| 
									
										
										
										
											2025-07-16 21:01:24 -04:00
										 |  |  |  | 			.filter((x) => x[1].ts < now) | 
					
						
							| 
									
										
										
										
											2025-01-14 20:15:18 -05:00
										 |  |  |  | 			.filter((x) => x[1].follow_depth > 1) | 
					
						
							| 
									
										
										
										
											2025-07-16 21:01:24 -04:00
										 |  |  |  | 			.sort(self.compare_follows) | 
					
						
							| 
									
										
										
										
											2025-01-14 20:15:18 -05:00
										 |  |  |  | 			.slice(0, 8) | 
					
						
							|  |  |  |  | 			.map((x) => x[0]); | 
					
						
							| 
									
										
										
										
											2025-01-12 14:54:09 -05:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 20:53:51 -04:00
										 |  |  |  | 	async enable_peer_exchange() { | 
					
						
							|  |  |  |  | 		await tfrpc.rpc.globalSettingsSet('peer_exchange', true); | 
					
						
							| 
									
										
										
										
											2025-06-14 20:27:19 -04:00
										 |  |  |  | 		await this.check_peer_exchange(); | 
					
						
							| 
									
										
										
										
											2025-06-11 20:53:51 -04:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 12:48:45 -04:00
										 |  |  |  | 	is_loading() { | 
					
						
							|  |  |  |  | 		return this.shadowRoot?.getElementById('news')?.loading; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-29 14:54:29 -05:00
										 |  |  |  | 	render_sidebar() { | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  |  | 		return html`
 | 
					
						
							| 
									
										
										
										
											2024-12-05 20:47:02 -05:00
										 |  |  |  | 			<div | 
					
						
							|  |  |  |  | 				class="w3-sidebar w3-bar-block w3-theme-d1 w3-collapse w3-animate-left" | 
					
						
							| 
									
										
										
										
											2024-12-29 12:44:42 -05:00
										 |  |  |  | 				style="width: 2in; left: 0; z-index: 5; box-sizing: border-box; top: 0" | 
					
						
							| 
									
										
										
										
											2024-12-05 20:47:02 -05:00
										 |  |  |  | 				id="sidebar" | 
					
						
							|  |  |  |  | 			> | 
					
						
							|  |  |  |  | 				<div | 
					
						
							|  |  |  |  | 					class="w3-right w3-button w3-hide-large" | 
					
						
							|  |  |  |  | 					@click=${this.hide_sidebar} | 
					
						
							|  |  |  |  | 				> | 
					
						
							|  |  |  |  | 					× | 
					
						
							|  |  |  |  | 				</div> | 
					
						
							|  |  |  |  | 				${this.hash.startsWith('##') && | 
					
						
							|  |  |  |  | 				this.channels.indexOf(this.hash.substring(2)) == -1 | 
					
						
							|  |  |  |  | 					? html`
 | 
					
						
							|  |  |  |  | 							<div class="w3-bar-item w3-theme-d2">Viewing</div> | 
					
						
							|  |  |  |  | 							<a | 
					
						
							|  |  |  |  | 								href="#" | 
					
						
							|  |  |  |  | 								class="w3-bar-item w3-button" | 
					
						
							|  |  |  |  | 								style="font-weight: bold" | 
					
						
							| 
									
										
										
										
											2025-10-28 12:41:59 -04:00
										 |  |  |  | 								>${this.hash.substring(1)}</a | 
					
						
							| 
									
										
										
										
											2024-12-05 20:47:02 -05:00
										 |  |  |  | 							> | 
					
						
							|  |  |  |  | 						`
 | 
					
						
							|  |  |  |  | 					: undefined} | 
					
						
							| 
									
										
										
										
											2025-01-12 14:54:09 -05:00
										 |  |  |  | 				<h4 class="w3-bar-item w3-theme-d2">Channels</h4> | 
					
						
							| 
									
										
										
										
											2024-12-05 20:47:02 -05:00
										 |  |  |  | 				<a | 
					
						
							|  |  |  |  | 					href="#" | 
					
						
							|  |  |  |  | 					class="w3-bar-item w3-button" | 
					
						
							|  |  |  |  | 					style=${this.hash == '#' ? 'font-weight: bold' : undefined} | 
					
						
							| 
									
										
										
										
											2024-12-29 15:15:28 -05:00
										 |  |  |  | 					>${this.unread_status('')}general</a | 
					
						
							| 
									
										
										
										
											2024-12-05 20:47:02 -05:00
										 |  |  |  | 				> | 
					
						
							|  |  |  |  | 				<a | 
					
						
							|  |  |  |  | 					href="#@" | 
					
						
							|  |  |  |  | 					class="w3-bar-item w3-button" | 
					
						
							|  |  |  |  | 					style=${this.hash == '#@' ? 'font-weight: bold' : undefined} | 
					
						
							| 
									
										
										
										
											2024-12-29 15:15:28 -05:00
										 |  |  |  | 					>${this.unread_status('@')}@mentions</a | 
					
						
							| 
									
										
										
										
											2024-12-05 20:47:02 -05:00
										 |  |  |  | 				> | 
					
						
							| 
									
										
										
										
											2025-06-04 18:00:46 -04:00
										 |  |  |  | 				<a | 
					
						
							|  |  |  |  | 					href="#👍" | 
					
						
							|  |  |  |  | 					class="w3-bar-item w3-button" | 
					
						
							|  |  |  |  | 					style=${this.hash == '#👍' ? 'font-weight: bold' : undefined} | 
					
						
							|  |  |  |  | 					>${this.unread_status('👍')}👍votes</a | 
					
						
							|  |  |  |  | 				> | 
					
						
							| 
									
										
										
										
											2025-10-26 12:46:06 -04:00
										 |  |  |  | 				${Object.keys(this?.visible_private_messages ?? []) | 
					
						
							| 
									
										
										
										
											2025-08-13 19:24:25 -04:00
										 |  |  |  | 					?.sort() | 
					
						
							|  |  |  |  | 					?.map( | 
					
						
							|  |  |  |  | 						(key) => html`
 | 
					
						
							|  |  |  |  | 							<a | 
					
						
							|  |  |  |  | 								href=${'#🔐' + JSON.parse(key).join(',')} | 
					
						
							|  |  |  |  | 								class="w3-bar-item w3-button" | 
					
						
							|  |  |  |  | 								style=${this.hash == '#🔐' + JSON.parse(key).join(',') | 
					
						
							|  |  |  |  | 									? 'font-weight: bold' | 
					
						
							|  |  |  |  | 									: undefined} | 
					
						
							| 
									
										
										
										
											2025-08-14 12:40:58 -04:00
										 |  |  |  | 								>${this.unread_status('🔐' + JSON.parse(key).join(','))} | 
					
						
							|  |  |  |  | 								${(key != '[]' ? JSON.parse(key) : [this.whoami]).map( | 
					
						
							| 
									
										
										
										
											2025-08-13 19:24:25 -04:00
										 |  |  |  | 									(id) => html`
 | 
					
						
							|  |  |  |  | 										<tf-user | 
					
						
							|  |  |  |  | 											id=${id} | 
					
						
							|  |  |  |  | 											nolink="true" | 
					
						
							|  |  |  |  | 											.users=${this.users} | 
					
						
							|  |  |  |  | 										></tf-user> | 
					
						
							|  |  |  |  | 									`
 | 
					
						
							|  |  |  |  | 								)}</a | 
					
						
							|  |  |  |  | 							> | 
					
						
							|  |  |  |  | 						`
 | 
					
						
							|  |  |  |  | 					)} | 
					
						
							| 
									
										
										
										
											2024-12-24 14:22:24 -05:00
										 |  |  |  | 				${Object.keys(this.drafts) | 
					
						
							|  |  |  |  | 					.sort() | 
					
						
							|  |  |  |  | 					.map( | 
					
						
							|  |  |  |  | 						(x) => html`
 | 
					
						
							|  |  |  |  | 							<a | 
					
						
							|  |  |  |  | 								href=${'#' + encodeURIComponent(x)} | 
					
						
							|  |  |  |  | 								class="w3-bar-item w3-button" | 
					
						
							|  |  |  |  | 								style="text-wrap: nowrap; text-overflow: ellipsis" | 
					
						
							|  |  |  |  | 								>📝 ${this.drafts[x]?.text ?? x}</a | 
					
						
							|  |  |  |  | 							> | 
					
						
							|  |  |  |  | 						`
 | 
					
						
							|  |  |  |  | 					)} | 
					
						
							| 
									
										
										
										
											2024-12-05 20:47:02 -05:00
										 |  |  |  | 				${this.channels.map( | 
					
						
							|  |  |  |  | 					(x) => html`
 | 
					
						
							|  |  |  |  | 						<a | 
					
						
							|  |  |  |  | 							href=${'#' + encodeURIComponent('#' + x)} | 
					
						
							|  |  |  |  | 							class="w3-bar-item w3-button" | 
					
						
							|  |  |  |  | 							style=${this.hash == '##' + x ? 'font-weight: bold' : undefined} | 
					
						
							| 
									
										
										
										
											2024-12-29 15:15:28 -05:00
										 |  |  |  | 							>${this.unread_status(x)}#${x}</a | 
					
						
							| 
									
										
										
										
											2024-12-05 20:47:02 -05:00
										 |  |  |  | 						> | 
					
						
							|  |  |  |  | 					`
 | 
					
						
							|  |  |  |  | 				)} | 
					
						
							| 
									
										
										
										
											2025-01-04 12:41:04 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-26 18:53:08 -04:00
										 |  |  |  | 				<a class="w3-bar-item w3-theme-d2 w3-button" href="#connections"> | 
					
						
							| 
									
										
										
										
											2025-04-27 09:53:24 -04:00
										 |  |  |  | 					<h4 style="margin: 0">Connections</h4> | 
					
						
							| 
									
										
										
										
											2025-04-26 18:53:08 -04:00
										 |  |  |  | 				</a> | 
					
						
							| 
									
										
										
										
											2025-06-11 20:53:51 -04:00
										 |  |  |  | 				${this.connections?.filter((x) => x.id)?.length == 0 | 
					
						
							|  |  |  |  | 					? html`
 | 
					
						
							|  |  |  |  | 							<button | 
					
						
							|  |  |  |  | 								class=${'w3-bar-item w3-button' + | 
					
						
							|  |  |  |  | 								(this.connections?.some((x) => x.flags.one_shot) | 
					
						
							|  |  |  |  | 									? ' w3-spin' | 
					
						
							|  |  |  |  | 									: '')} | 
					
						
							| 
									
										
										
										
											2025-07-02 12:41:03 -04:00
										 |  |  |  | 								@click=${() => | 
					
						
							|  |  |  |  | 									this.dispatchEvent( | 
					
						
							|  |  |  |  | 										new Event('refresh', {bubbles: true, composed: true}) | 
					
						
							|  |  |  |  | 									)} | 
					
						
							| 
									
										
										
										
											2025-06-11 20:53:51 -04:00
										 |  |  |  | 							> | 
					
						
							|  |  |  |  | 								↻ Sync now | 
					
						
							|  |  |  |  | 							</button> | 
					
						
							| 
									
										
										
										
											2025-10-01 19:12:31 -04:00
										 |  |  |  | 							<button | 
					
						
							|  |  |  |  | 								class="w3-bar-item w3-button w3-ripple" | 
					
						
							|  |  |  |  | 								@click=${() => | 
					
						
							|  |  |  |  | 									this.dispatchEvent( | 
					
						
							|  |  |  |  | 										new Event('toggle_stay_connected', { | 
					
						
							|  |  |  |  | 											bubbles: true, | 
					
						
							|  |  |  |  | 											composed: true, | 
					
						
							|  |  |  |  | 										}) | 
					
						
							|  |  |  |  | 									)} | 
					
						
							|  |  |  |  | 							> | 
					
						
							|  |  |  |  | 								<span style="display: inline-block; width: 1.8em" | 
					
						
							|  |  |  |  | 									>${this.stay_connected ? '🔗' : '⛓️💥'}</span | 
					
						
							|  |  |  |  | 								> | 
					
						
							|  |  |  |  | 								${this.stay_connected ? 'Online mode' : 'Passive mode'} | 
					
						
							|  |  |  |  | 							</button> | 
					
						
							| 
									
										
										
										
											2025-06-11 20:53:51 -04:00
										 |  |  |  | 							<button | 
					
						
							| 
									
										
										
										
											2025-10-29 12:40:28 -04:00
										 |  |  |  | 								class=${'w3-bar-item w3-button w3-border w3-leftbar w3-rightbar' + | 
					
						
							| 
									
										
										
										
											2025-06-14 20:27:19 -04:00
										 |  |  |  | 								(this.peer_exchange !== false ? ' w3-hide' : '')} | 
					
						
							| 
									
										
										
										
											2025-06-11 20:53:51 -04:00
										 |  |  |  | 								@click=${this.enable_peer_exchange} | 
					
						
							|  |  |  |  | 							> | 
					
						
							| 
									
										
										
										
											2025-10-29 12:40:28 -04:00
										 |  |  |  | 								🔍🌐 Use publicly advertised peers | 
					
						
							| 
									
										
										
										
											2025-06-11 20:53:51 -04:00
										 |  |  |  | 							</button> | 
					
						
							|  |  |  |  | 						`
 | 
					
						
							|  |  |  |  | 					: undefined} | 
					
						
							| 
									
										
										
										
											2025-01-20 16:57:22 -05:00
										 |  |  |  | 				${this.connections | 
					
						
							| 
									
										
										
										
											2025-05-31 11:28:09 -04:00
										 |  |  |  | 					.filter((x) => x.id) | 
					
						
							| 
									
										
										
										
											2025-01-20 16:57:22 -05:00
										 |  |  |  | 					.map( | 
					
						
							|  |  |  |  | 						(x) => html`
 | 
					
						
							|  |  |  |  | 							<tf-user | 
					
						
							|  |  |  |  | 								class="w3-bar-item" | 
					
						
							| 
									
										
										
										
											2025-05-31 11:28:09 -04:00
										 |  |  |  | 								style=${x.destroy_reason | 
					
						
							|  |  |  |  | 									? 'border-left: 4px solid red; border-right: 4px solid red' | 
					
						
							|  |  |  |  | 									: x.connected | 
					
						
							|  |  |  |  | 										? x.flags?.one_shot | 
					
						
							|  |  |  |  | 											? 'border-left: 4px solid blue; border-right: 4px solid blue' | 
					
						
							|  |  |  |  | 											: 'border-left: 4px solid green; border-right: 4px solid green' | 
					
						
							|  |  |  |  | 										: ''} | 
					
						
							| 
									
										
										
										
											2025-01-20 16:57:22 -05:00
										 |  |  |  | 								id=${x.id} | 
					
						
							| 
									
										
										
										
											2025-04-12 07:05:37 -04:00
										 |  |  |  | 								fallback_name=${x.host} | 
					
						
							| 
									
										
										
										
											2025-01-20 16:57:22 -05:00
										 |  |  |  | 								.users=${this.users} | 
					
						
							|  |  |  |  | 							></tf-user> | 
					
						
							|  |  |  |  | 						`
 | 
					
						
							|  |  |  |  | 					)} | 
					
						
							| 
									
										
										
										
											2025-01-12 14:54:09 -05:00
										 |  |  |  | 				<h4 class="w3-bar-item w3-theme-d2">Suggested Follows</h4> | 
					
						
							|  |  |  |  | 				${this.suggested_follows().map( | 
					
						
							|  |  |  |  | 					(x) => html`
 | 
					
						
							|  |  |  |  | 						<tf-user | 
					
						
							|  |  |  |  | 							class="w3-bar-item" | 
					
						
							|  |  |  |  | 							style="max-width: 100%" | 
					
						
							|  |  |  |  | 							id=${x} | 
					
						
							|  |  |  |  | 							.users=${this.users} | 
					
						
							|  |  |  |  | 						></tf-user> | 
					
						
							|  |  |  |  | 					`
 | 
					
						
							|  |  |  |  | 				)} | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  |  | 			</div> | 
					
						
							| 
									
										
										
										
											2024-12-05 20:47:02 -05:00
										 |  |  |  | 			<div | 
					
						
							|  |  |  |  | 				class="w3-overlay" | 
					
						
							|  |  |  |  | 				id="sidebar_overlay" | 
					
						
							|  |  |  |  | 				@click=${this.hide_sidebar} | 
					
						
							|  |  |  |  | 			></div> | 
					
						
							| 
									
										
										
										
											2024-12-29 14:54:29 -05:00
										 |  |  |  | 		`;
 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	render() { | 
					
						
							|  |  |  |  | 		let profile = | 
					
						
							|  |  |  |  | 			this.hash.startsWith('#@') && this.hash != '#@' | 
					
						
							| 
									
										
										
										
											2025-01-27 21:02:15 -05:00
										 |  |  |  | 				? keyed( | 
					
						
							|  |  |  |  | 						this.hash.substring(1), | 
					
						
							|  |  |  |  | 						html`<tf-profile
 | 
					
						
							|  |  |  |  | 							class="tf-profile" | 
					
						
							|  |  |  |  | 							id=${this.hash.substring(1)} | 
					
						
							|  |  |  |  | 							whoami=${this.whoami} | 
					
						
							|  |  |  |  | 							.users=${this.users} | 
					
						
							|  |  |  |  | 						></tf-profile>` | 
					
						
							|  |  |  |  | 					) | 
					
						
							| 
									
										
										
										
											2024-12-29 14:54:29 -05:00
										 |  |  |  | 				: undefined; | 
					
						
							|  |  |  |  | 		let edit_profile; | 
					
						
							|  |  |  |  | 		if ( | 
					
						
							|  |  |  |  | 			!this.loading && | 
					
						
							|  |  |  |  | 			this.users[this.whoami]?.name === undefined && | 
					
						
							|  |  |  |  | 			this.hash.substring(1) != this.whoami | 
					
						
							|  |  |  |  | 		) { | 
					
						
							|  |  |  |  | 			edit_profile = html` <div
 | 
					
						
							|  |  |  |  | 				class="w3-panel w3-padding w3-round w3-card-4 w3-theme-l3" | 
					
						
							|  |  |  |  | 			> | 
					
						
							|  |  |  |  | 				ℹ️ Follow your identity link ☝️ above to edit your profile and set your | 
					
						
							|  |  |  |  | 				name. | 
					
						
							|  |  |  |  | 			</div>`; | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-01-11 14:09:42 -05:00
										 |  |  |  | 		return cache(html`
 | 
					
						
							| 
									
										
										
										
											2025-10-22 19:39:20 -04:00
										 |  |  |  | 			<style> | 
					
						
							|  |  |  |  | 				${generate_theme()} | 
					
						
							|  |  |  |  | 			</style> | 
					
						
							| 
									
										
										
										
											2024-12-29 14:54:29 -05:00
										 |  |  |  | 			${this.render_sidebar()} | 
					
						
							| 
									
										
										
										
											2024-12-29 13:32:37 -05:00
										 |  |  |  | 			<div | 
					
						
							| 
									
										
										
										
											2025-09-09 19:27:32 -04:00
										 |  |  |  | 				style="margin-left: 2in; padding: 0px; top: 0; height: 100vh; max-height: 100%; overflow: auto; contain: layout" | 
					
						
							| 
									
										
										
										
											2024-12-29 13:32:37 -05:00
										 |  |  |  | 				id="main" | 
					
						
							|  |  |  |  | 				class="w3-main" | 
					
						
							|  |  |  |  | 			> | 
					
						
							| 
									
										
										
										
											2024-12-29 12:44:42 -05:00
										 |  |  |  | 				<div style="padding: 8px"> | 
					
						
							|  |  |  |  | 					<p> | 
					
						
							|  |  |  |  | 						${this.hash.startsWith('##') | 
					
						
							|  |  |  |  | 							? html`
 | 
					
						
							|  |  |  |  | 									<button | 
					
						
							|  |  |  |  | 										class="w3-button w3-theme-d1" | 
					
						
							|  |  |  |  | 										@click=${this.channel_toggle_subscribed} | 
					
						
							|  |  |  |  | 									> | 
					
						
							|  |  |  |  | 										${this.channels.indexOf(this.hash.substring(2)) != -1 | 
					
						
							|  |  |  |  | 											? 'Unsubscribe from #' | 
					
						
							|  |  |  |  | 											: 'Subscribe to #'}${this.hash.substring(2)} | 
					
						
							|  |  |  |  | 									</button> | 
					
						
							|  |  |  |  | 								`
 | 
					
						
							|  |  |  |  | 							: undefined} | 
					
						
							|  |  |  |  | 					</p> | 
					
						
							| 
									
										
										
										
											2024-12-29 15:11:14 -05:00
										 |  |  |  | 					<div> | 
					
						
							|  |  |  |  | 						<div | 
					
						
							|  |  |  |  | 							id="show_sidebar" | 
					
						
							|  |  |  |  | 							class="w3-button w3-hide-large" | 
					
						
							|  |  |  |  | 							@click=${this.show_sidebar} | 
					
						
							|  |  |  |  | 						> | 
					
						
							| 
									
										
										
										
											2025-05-07 19:59:39 -04:00
										 |  |  |  | 							${this.unread_status()}☰ | 
					
						
							| 
									
										
										
										
											2024-12-29 15:11:14 -05:00
										 |  |  |  | 						</div> | 
					
						
							| 
									
										
										
										
											2024-12-29 12:44:42 -05:00
										 |  |  |  | 						Welcome, <tf-user id=${this.whoami} .users=${this.users}></tf-user>! | 
					
						
							|  |  |  |  | 						${edit_profile} | 
					
						
							|  |  |  |  | 					</div> | 
					
						
							|  |  |  |  | 					<div> | 
					
						
							|  |  |  |  | 						<tf-compose | 
					
						
							|  |  |  |  | 							id="tf-compose" | 
					
						
							|  |  |  |  | 							whoami=${this.whoami} | 
					
						
							|  |  |  |  | 							.users=${this.users} | 
					
						
							|  |  |  |  | 							.drafts=${this.drafts} | 
					
						
							|  |  |  |  | 							@tf-draft=${this.draft} | 
					
						
							|  |  |  |  | 							.channel=${this.channel()} | 
					
						
							| 
									
										
										
										
											2025-08-13 19:53:28 -04:00
										 |  |  |  | 							.recipients=${this.hash.startsWith('#🔐') | 
					
						
							|  |  |  |  | 								? this.hash.substring('#🔐'.length).split(',') | 
					
						
							|  |  |  |  | 								: undefined} | 
					
						
							| 
									
										
										
										
											2024-12-29 12:44:42 -05:00
										 |  |  |  | 						></tf-compose> | 
					
						
							|  |  |  |  | 					</div> | 
					
						
							|  |  |  |  | 					${profile} | 
					
						
							|  |  |  |  | 					<tf-tab-news-feed | 
					
						
							|  |  |  |  | 						id="news" | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  |  | 						whoami=${this.whoami} | 
					
						
							|  |  |  |  | 						.users=${this.users} | 
					
						
							| 
									
										
										
										
											2024-12-29 12:44:42 -05:00
										 |  |  |  | 						.following=${this.following} | 
					
						
							|  |  |  |  | 						hash=${this.hash} | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  |  | 						.drafts=${this.drafts} | 
					
						
							| 
									
										
										
										
											2024-12-29 12:44:42 -05:00
										 |  |  |  | 						.expanded=${this.expanded} | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  |  | 						@tf-draft=${this.draft} | 
					
						
							| 
									
										
										
										
											2024-12-29 12:44:42 -05:00
										 |  |  |  | 						@tf-expand=${this.on_expand} | 
					
						
							|  |  |  |  | 						.channels_unread=${this.channels_unread} | 
					
						
							|  |  |  |  | 						.channels_latest=${this.channels_latest} | 
					
						
							| 
									
										
										
										
											2025-02-05 18:41:37 -05:00
										 |  |  |  | 						.private_messages=${this.private_messages} | 
					
						
							| 
									
										
										
										
											2025-08-13 19:16:34 -04:00
										 |  |  |  | 						.grouped_private_messages=${this.grouped_private_messages} | 
					
						
							| 
									
										
										
										
											2025-04-29 20:48:47 -04:00
										 |  |  |  | 						.recent_reactions=${this.recent_reactions} | 
					
						
							| 
									
										
										
										
											2024-12-29 12:44:42 -05:00
										 |  |  |  | 					></tf-tab-news-feed> | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  |  | 				</div> | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  |  | 			</div> | 
					
						
							| 
									
										
										
										
											2025-01-11 14:09:42 -05:00
										 |  |  |  | 		`);
 | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-03 00:30:48 +00:00
										 |  |  |  | customElements.define('tf-tab-news', TfTabNewsElement); |