forked from cory/tildefriends
		
	Docs and emoji picker and probably some other random app updates.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4124 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
		@@ -1 +1 @@
 | 
				
			|||||||
{"type":"tildefriends-app","files":{"app.js":"&WEvJYebSMi5d2eXgUwJJmvR/Q4slFg3zHYB8Q2mXJII=.sha256","index.md":"&Pi0NTJn9/w76yIUKqRRuSvUPSpqkxdYynmjeOBbF3K8=.sha256","todo.md":"&d8Kq8yuOn8SL3tJVy9BiDXHAe/jverpBj5AMLWLtmFM=.sha256","structure.md":"&T+CBfT9XP6ooKFvD1ZCI9hsutqsNIamfBxtAho0HtlU=.sha256","guide.md":"&SgnGL0+rjetY2o9A2+lVRbNvHIkqKwMnZr9gXWneIlc=.sha256","ssb.md":"&ouqT3XzTGfBNpOP/uEdOw7K1F9BeLZgQCx24XTvhyXU=.sha256"}}
 | 
					{"type":"tildefriends-app","files":{"app.js":"&WEvJYebSMi5d2eXgUwJJmvR/Q4slFg3zHYB8Q2mXJII=.sha256","index.md":"&79+ntX4sRvg+MboV5nMFz01BSicxsWIQRx719VHS8uk=.sha256","todo.md":"&vLL7JVe1FcqOcYmd22KMkIw3T2IrEbxyonMw5rdICjA=.sha256","structure.md":"&jph8x/fMXKOd4I0ZiUVb0ZLTfPQ7gBWoxJPrvtX6vtw=.sha256","guide.md":"&SgnGL0+rjetY2o9A2+lVRbNvHIkqKwMnZr9gXWneIlc=.sha256","ssb.md":"&JH1JfoTaCcUifCpnAwhImKBACI0PHoLhoOw1WAnWpLw=.sha256","vision.md":"&v2wu2MGlhNvaALQQ9rGna7ZeEQWSghFgQcDfD5xEyE0=.sha256"}}
 | 
				
			||||||
@@ -2,9 +2,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Tilde Friends is a participating member of a greater social
 | 
					Tilde Friends is a participating member of a greater social
 | 
				
			||||||
network, [Secure Scuttlebutt](https://scuttlebutt.nz/),
 | 
					network, [Secure Scuttlebutt](https://scuttlebutt.nz/),
 | 
				
			||||||
augmenting it with a way to safely and securely write, share,
 | 
					adding a way to safely and securely write, share,
 | 
				
			||||||
and run code.
 | 
					and run code in the form of server-side web applications.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- [Tilde Friends Vision](#vision)
 | 
				
			||||||
- [Secure Scuttlebutt from Scratch](#ssb)
 | 
					- [Secure Scuttlebutt from Scratch](#ssb)
 | 
				
			||||||
- [Structure](#structure)
 | 
					- [Structure](#structure)
 | 
				
			||||||
- [Guide](#guide)
 | 
					- [Guide](#guide)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,8 @@ IPv4 addresses.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
So be prepared to accept variations.
 | 
					So be prepared to accept variations.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There also an undocumented "new" style of discovery message.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Secret Handshake, Box Stream, and RPC Protocol
 | 
					## Secret Handshake, Box Stream, and RPC Protocol
 | 
				
			||||||
Now that two clients are aware of eachother, they need to complete a secret handshake.
 | 
					Now that two clients are aware of eachother, they need to complete a secret handshake.
 | 
				
			||||||
The [programming guide](https://ssbc.github.io/scuttlebutt-protocol-guide/#handshake)
 | 
					The [programming guide](https://ssbc.github.io/scuttlebutt-protocol-guide/#handshake)
 | 
				
			||||||
@@ -26,12 +28,14 @@ The box stream and RPC protocol can both be implemented from the
 | 
				
			|||||||
without surprises.
 | 
					without surprises.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Synchronizing Data
 | 
					## Synchronizing Data
 | 
				
			||||||
So now you're discovering other clients on the local network, connecting, performing
 | 
					
 | 
				
			||||||
a secret handshake, and making remote procedure calls over box streams.  The next step
 | 
					... `ebt.replicate` or `createHistoryStream` ...
 | 
				
			||||||
is to start synchronizing feeds over the network.  The goal, after all, is to author
 | 
					
 | 
				
			||||||
messages in your local append-only log and have them show up in distant clients, or
 | 
					## Rooms
 | 
				
			||||||
vice versa.
 | 
					
 | 
				
			||||||
 | 
					TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## References
 | 
					## References
 | 
				
			||||||
* [https://ssbc.github.io/scuttlebutt-protocol-guide/](https://ssbc.github.io/scuttlebutt-protocol-guide/)
 | 
					* [https://ssbc.github.io/scuttlebutt-protocol-guide/](https://ssbc.github.io/scuttlebutt-protocol-guide/)
 | 
				
			||||||
* [https://dev.planetary.social/](https://dev.planetary.social/)
 | 
					* [https://dev.planetary.social/](https://dev.planetary.social/)
 | 
				
			||||||
 | 
					* [https://dev.scuttlebutt.nz/#/golang/?id=muxrpc-endpoints](https://dev.scuttlebutt.nz/#/golang/?id=muxrpc-endpoints)
 | 
				
			||||||
@@ -21,7 +21,7 @@ In combines the following key components:
 | 
				
			|||||||
  are mediated through the core process.
 | 
					  are mediated through the core process.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
When run with no arguments, it starts a web server on
 | 
					When run with no arguments, it starts a web server on
 | 
				
			||||||
[http://localhost:12345/](http://localhost:12345/) and an SSB server.
 | 
					[http://localhost:12345/](http://localhost:12345/) and an SSB node.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Web Interface
 | 
					## Web Interface
 | 
				
			||||||
The Tilde Friends web server provides access to Tilde Friends applications,
 | 
					The Tilde Friends web server provides access to Tilde Friends applications,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,6 @@
 | 
				
			|||||||
- Sync status (problem feeds, messages/seconds stats, ...)
 | 
					- Sync status (problem feeds, messages/seconds stats, ...)
 | 
				
			||||||
- app: wiki
 | 
					- app: wiki
 | 
				
			||||||
- app: public blog
 | 
					- app: public blog
 | 
				
			||||||
- app: build archive
 | 
					 | 
				
			||||||
- app: todo
 | 
					 | 
				
			||||||
- Content-Disposition: download
 | 
					- Content-Disposition: download
 | 
				
			||||||
- remove SSB credentials
 | 
					- remove SSB credentials
 | 
				
			||||||
- export SSB credentials
 | 
					- export SSB credentials
 | 
				
			||||||
@@ -22,7 +20,6 @@
 | 
				
			|||||||
- fix weird HTTP warnings
 | 
					- fix weird HTTP warnings
 | 
				
			||||||
- ssb from child process?
 | 
					- ssb from child process?
 | 
				
			||||||
- channels
 | 
					- channels
 | 
				
			||||||
- image downsample
 | 
					 | 
				
			||||||
- placeholder/missing images
 | 
					- placeholder/missing images
 | 
				
			||||||
- no denial of service
 | 
					- no denial of service
 | 
				
			||||||
- package standalone executable
 | 
					- package standalone executable
 | 
				
			||||||
@@ -30,12 +27,16 @@
 | 
				
			|||||||
- editor without app iframe
 | 
					- editor without app iframe
 | 
				
			||||||
- sequence_before_author -> flags
 | 
					- sequence_before_author -> flags
 | 
				
			||||||
- linkify ssb: links
 | 
					- linkify ssb: links
 | 
				
			||||||
 | 
					- perfect rooms support
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## MVP2
 | 
					## MVP2
 | 
				
			||||||
- connections 2.0
 | 
					- connections 2.0
 | 
				
			||||||
- make a better connections API
 | 
					- make a better connections API
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Maybe Done
 | 
					## Maybe Done
 | 
				
			||||||
 | 
					- image downsample
 | 
				
			||||||
 | 
					- app: todo
 | 
				
			||||||
 | 
					- app: build archive
 | 
				
			||||||
- update README
 | 
					- update README
 | 
				
			||||||
- administrators config	
 | 
					- administrators config	
 | 
				
			||||||
- apps name characters
 | 
					- apps name characters
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										62
									
								
								apps/cory/docs/vision.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								apps/cory/docs/vision.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					# Tilde Friends Vision
 | 
				
			||||||
 | 
					[Back to index](#index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tilde Friends is a tool for making and sharing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is both a peer-to-peer social network client, participating in Secure
 | 
				
			||||||
 | 
					Scuttlebutt, and an environment for creating and running web applications.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Why
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This is a thing that I wanted to exist and wanted to work on.  No other reason.
 | 
				
			||||||
 | 
					There is not a business model.  I believe it is interesting and unique.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Goals
 | 
				
			||||||
 | 
					1. Make it **easy and fun** to run all sorts of web applications.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. Provide **security** that is easy to understand and protects your data.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. Make **creating and sharing** web applications accessible to anyone with a
 | 
				
			||||||
 | 
					   browser.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Ways to Use Tilde Friends
 | 
				
			||||||
 | 
					1. **Social Network User**: This is a social network first.  You are just here,
 | 
				
			||||||
 | 
					   because your friends are.  Or you like how we limit your message length or
 | 
				
			||||||
 | 
					   short videos or whatever the trend is.  If you are ambitious, you click links
 | 
				
			||||||
 | 
					   and see interactive experiences (apps) that you wouldn't see elsewhere.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. **Web Visitor**: You get links from a friend to meeting invites, polls, games,
 | 
				
			||||||
 | 
					   lists, wiki pages, ..., and you interact with them as though they were
 | 
				
			||||||
 | 
					   cloud-hosted by a megacorporation.  They just work, and you don't think twice.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. **Group leader**: You host or use a small public instance, installing apps for
 | 
				
			||||||
 | 
					   a group of friends to use as web visitors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4. **Developer**: You like to write code and make or improve apps for fun or to
 | 
				
			||||||
 | 
					   solve problems.  When you encounter a Tilde Friends app on a strange server,
 | 
				
			||||||
 | 
					   you know you can trivially modify it or download it to your own instance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Future Goals / Endgame
 | 
				
			||||||
 | 
					1. Mobile apps.  This can run on your old phone.  Maybe you won't be hosting
 | 
				
			||||||
 | 
					   the web interface publicly, but you can sync, install and edit apps, and
 | 
				
			||||||
 | 
					   otherwise get the full experience from a tiny touch screen.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. The universal application runtime.  The web browser is the universal
 | 
				
			||||||
 | 
					   platform, but even for the simplest application that you might want to host
 | 
				
			||||||
 | 
					   for your friends, cloud hosting, containers, and complicated dependencies might
 | 
				
			||||||
 | 
					   all enter the mix.  Tilde Friends, though it is yet another thing to host,
 | 
				
			||||||
 | 
					   includes everything you need out of the box to run a vast variety of interesting
 | 
				
			||||||
 | 
					   apps.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Tilde Friends will be built out, gradually providing safe access to host
 | 
				
			||||||
 | 
					   resources and client resources the same way web browsers extended access to
 | 
				
			||||||
 | 
					   resources like GPU, persistent storage, cameras, ... over the years.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Not much effort has been put forward yet to having a robust, long-lasting API,
 | 
				
			||||||
 | 
					   but since the client side longevity is already handled by web browsers, it
 | 
				
			||||||
 | 
					   seems possible that the server-side API can be managed in a similar way.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. An awesome development environment.  Right now it runs JavaScript from the
 | 
				
			||||||
 | 
					   first embeddable text editor I could poorly configure enough to edit code,
 | 
				
			||||||
 | 
					   but it could incorporate a debugger, source control integration a la ssb-git,
 | 
				
			||||||
 | 
					   merge tools, and transpiling from all sorts of different languages.
 | 
				
			||||||
@@ -1 +1 @@
 | 
				
			|||||||
{"type":"tildefriends-app","files":{"app.js":"&gxOJaVf/HdjVJVC9NvZ9n3/825OD1xMMHdF/dFQwe24=.sha256","lit-all.min.js":"&XKgdRySJuiZeZvchNFGjVWn0XOVhQFmG7/HTWYQ8s68=.sha256","index.html":"&TxhFekB9ov7tf/fmkAg7x5797i27oLidhgxEfDKC0T0=.sha256","script.js":"&G8puK9Q4MngHy3D4ppcKyT49WKbHD2OCeUcAw2ghTDE=.sha256","lit-all.min.js.map":"&lA9iFp1YbqSndxXZuwtgmrj7NDMkN71nJITbtjWL3VA=.sha256","tf-id-picker.js":"&maN8DUFrmRxW5nsVyOAMk5k1ekcz/pfzvSS99ac3jo8=.sha256","tf-app.js":"&7hclNu41CIoNk1JlXHiYmDPDyDIICZfMickJYtnF5eQ=.sha256","tf-message.js":"&oXFucwmn16nvKslQoGKTppO+71EoDZJE54z3WrlNUPI=.sha256","tf-user.js":"&bXTedgBudTQLXEBPY9R8OLfQ/ZLpo8YRU9Oq/wuGG3Y=.sha256","tf-utils.js":"&6RQUuxB3PkOhYEJr9+89Ptx7uijczjn0r035yCcQOQQ=.sha256","commonmark.min.js":"&bfBaMLU19d1p/vPBF9hlARqDX002KXG/UOfxOahZhe4=.sha256","tf-compose.js":"&y+Q47tdm60Od1UzuRu7OOLwineyQCL1LIb3KP5IwHTY=.sha256","emojis.json":"&h3P4pez+AI4aYdsN0dJ3pbUEFR0276t9AM20caj/W/s=.sha256","emojis.js":"&pqYLDE/13PyEt2ceeFqvnwZ8NqWfPfpDBt4vP8SeHbs=.sha256","tf-styles.js":"&LFeL/vWgrv4N8q/mBrQAnhbaOI+dXNJYvH9bn1bXSqQ=.sha256","tf-profile.js":"&vRKjsnYvOiHCQahzEfznCvP5YDwUPtltlpWf+pxwZ1Y=.sha256","commonmark-linkify.js":"&X+hNNkmSRvKY86khyAun+cXksquXbMakZdINbGbx30g=.sha256","tf-tab-search.js":"&ESt2vMG19sH5j6ungKua/ZuvIGslyuWyb3juXdOCecg=.sha256","tf-tab-news.js":"&F7T3LVS867x7vsKhYRR7eLNdCFZmrZ3JzEMfJEEKRm0=.sha256","tf-tab-connections.js":"&Ftt5RnkrhndV2lwC7XXUZX8JiUODqPjqEVgSTJQD6JU=.sha256","tf-news.js":"&gfG5LwXpugDkwDCOCOxQnNn0jLURZexSmvDu4SpQohA=.sha256","tribute.css":"&9FogMzZHKXCfGb7mlh7z+/wiNZzBsOB/tKoh6MfYJno=.sha256","tribute.esm.js":"&P1wKqCfYULpR/ahSB98JP8xaxfikuZwwtT6I/SAo7/Y=.sha256","commonmark-hashtag.js":"&H+V1OLA9GDdzycKclz276zAtSZLpT3rlNVa4+qQmp4o=.sha256"}}
 | 
					{"type":"tildefriends-app","files":{"app.js":"&gxOJaVf/HdjVJVC9NvZ9n3/825OD1xMMHdF/dFQwe24=.sha256","lit-all.min.js":"&XKgdRySJuiZeZvchNFGjVWn0XOVhQFmG7/HTWYQ8s68=.sha256","index.html":"&TxhFekB9ov7tf/fmkAg7x5797i27oLidhgxEfDKC0T0=.sha256","script.js":"&G8puK9Q4MngHy3D4ppcKyT49WKbHD2OCeUcAw2ghTDE=.sha256","lit-all.min.js.map":"&lA9iFp1YbqSndxXZuwtgmrj7NDMkN71nJITbtjWL3VA=.sha256","tf-id-picker.js":"&maN8DUFrmRxW5nsVyOAMk5k1ekcz/pfzvSS99ac3jo8=.sha256","tf-app.js":"&7hclNu41CIoNk1JlXHiYmDPDyDIICZfMickJYtnF5eQ=.sha256","tf-message.js":"&oXFucwmn16nvKslQoGKTppO+71EoDZJE54z3WrlNUPI=.sha256","tf-user.js":"&bXTedgBudTQLXEBPY9R8OLfQ/ZLpo8YRU9Oq/wuGG3Y=.sha256","tf-utils.js":"&6RQUuxB3PkOhYEJr9+89Ptx7uijczjn0r035yCcQOQQ=.sha256","commonmark.min.js":"&bfBaMLU19d1p/vPBF9hlARqDX002KXG/UOfxOahZhe4=.sha256","tf-compose.js":"&iIQ8FAqBiaOfjLvXwL8X1ewkhBqiZNo2jwnlSzui+bY=.sha256","emojis.json":"&h3P4pez+AI4aYdsN0dJ3pbUEFR0276t9AM20caj/W/s=.sha256","emojis.js":"&NC9VddNdX+ZpyIDUQJvH2y1u3ZczQub5+bNmN9ndj7I=.sha256","tf-styles.js":"&LFeL/vWgrv4N8q/mBrQAnhbaOI+dXNJYvH9bn1bXSqQ=.sha256","tf-profile.js":"&vRKjsnYvOiHCQahzEfznCvP5YDwUPtltlpWf+pxwZ1Y=.sha256","commonmark-linkify.js":"&X+hNNkmSRvKY86khyAun+cXksquXbMakZdINbGbx30g=.sha256","tf-tab-search.js":"&ESt2vMG19sH5j6ungKua/ZuvIGslyuWyb3juXdOCecg=.sha256","tf-tab-news.js":"&F7T3LVS867x7vsKhYRR7eLNdCFZmrZ3JzEMfJEEKRm0=.sha256","tf-tab-connections.js":"&Ftt5RnkrhndV2lwC7XXUZX8JiUODqPjqEVgSTJQD6JU=.sha256","tf-news.js":"&gfG5LwXpugDkwDCOCOxQnNn0jLURZexSmvDu4SpQohA=.sha256","tribute.css":"&9FogMzZHKXCfGb7mlh7z+/wiNZzBsOB/tKoh6MfYJno=.sha256","tribute.esm.js":"&P1wKqCfYULpR/ahSB98JP8xaxfikuZwwtT6I/SAo7/Y=.sha256","commonmark-hashtag.js":"&H+V1OLA9GDdzycKclz276zAtSZLpT3rlNVa4+qQmp4o=.sha256"}}
 | 
				
			||||||
@@ -24,20 +24,41 @@ export function picker(callback, anchor) {
 | 
				
			|||||||
		div.style.border = '1px solid #000';
 | 
							div.style.border = '1px solid #000';
 | 
				
			||||||
		div.style.display = 'block';
 | 
							div.style.display = 'block';
 | 
				
			||||||
		div.style.position = 'absolute';
 | 
							div.style.position = 'absolute';
 | 
				
			||||||
 | 
							div.style.minWidth = '16em';
 | 
				
			||||||
 | 
							div.style.width = '16em';
 | 
				
			||||||
		div.style.maxWidth = '16em';
 | 
							div.style.maxWidth = '16em';
 | 
				
			||||||
		div.style.maxHeight = '16em';
 | 
							div.style.maxHeight = '16em';
 | 
				
			||||||
		div.style.overflow = 'scroll';
 | 
							div.style.overflow = 'scroll';
 | 
				
			||||||
		div.style.fontWeight = 'bold';
 | 
							div.style.fontWeight = 'bold';
 | 
				
			||||||
 | 
							div.style.fontSize = 'xx-large';
 | 
				
			||||||
		let input = document.createElement('input');
 | 
							let input = document.createElement('input');
 | 
				
			||||||
		input.type = 'text';
 | 
							input.type = 'text';
 | 
				
			||||||
 | 
							input.style.display = 'block';
 | 
				
			||||||
 | 
							input.style.boxSizing = 'border-box';
 | 
				
			||||||
 | 
							input.style.width = '100%';
 | 
				
			||||||
 | 
							input.style.margin = '0';
 | 
				
			||||||
 | 
							input.style.position = 'relative';
 | 
				
			||||||
		div.appendChild(input);
 | 
							div.appendChild(input);
 | 
				
			||||||
		let list = document.createElement('div');
 | 
							let list = document.createElement('div');
 | 
				
			||||||
		div.appendChild(list);
 | 
							div.appendChild(list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							function cleanup() {
 | 
				
			||||||
 | 
								div.parentElement.removeChild(div);
 | 
				
			||||||
 | 
								window.removeEventListener('keydown', key_down);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							function key_down(event) {
 | 
				
			||||||
 | 
								if (event.key == 'Escape') {
 | 
				
			||||||
 | 
									cleanup();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		function refresh() {
 | 
							function refresh() {
 | 
				
			||||||
			while (list.firstChild) {
 | 
								while (list.firstChild) {
 | 
				
			||||||
				list.removeChild(list.firstChild);
 | 
									list.removeChild(list.firstChild);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			let search = input.value;
 | 
								let search = input.value;
 | 
				
			||||||
 | 
								let any_at_all = false;
 | 
				
			||||||
			Object.entries(json).forEach(function(row) {
 | 
								Object.entries(json).forEach(function(row) {
 | 
				
			||||||
				let header = document.createElement('div');
 | 
									let header = document.createElement('div');
 | 
				
			||||||
				header.appendChild(document.createTextNode(row[0]));
 | 
									header.appendChild(document.createTextNode(row[0]));
 | 
				
			||||||
@@ -51,28 +72,25 @@ export function picker(callback, anchor) {
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
					let emoji = document.createElement('span');
 | 
										let emoji = document.createElement('span');
 | 
				
			||||||
					const k_size = '1.25em';
 | 
										const k_size = '1.25em';
 | 
				
			||||||
					emoji.style.width = k_size;
 | 
					 | 
				
			||||||
					emoji.style.maxWidth = k_size;
 | 
					 | 
				
			||||||
					emoji.style.minWidth = k_size;
 | 
					 | 
				
			||||||
					emoji.style.height = k_size;
 | 
					 | 
				
			||||||
					emoji.style.maxHeight = k_size;
 | 
					 | 
				
			||||||
					emoji.style.minHeight = k_size;
 | 
					 | 
				
			||||||
					emoji.style.display = 'inline-block';
 | 
										emoji.style.display = 'inline-block';
 | 
				
			||||||
					emoji.style.overflow = 'hidden';
 | 
										emoji.style.overflow = 'hidden';
 | 
				
			||||||
					emoji.style.cursor = 'pointer';
 | 
										emoji.style.cursor = 'pointer';
 | 
				
			||||||
					emoji.onclick = function() {
 | 
										emoji.onclick = function() {
 | 
				
			||||||
						callback(entry);
 | 
											callback(entry);
 | 
				
			||||||
						div.parentElement.removeChild(div);
 | 
					 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					emoji.title = entry.name;
 | 
										emoji.title = entry.name;
 | 
				
			||||||
					emoji.appendChild(document.createTextNode(entry.emoji));
 | 
										emoji.appendChild(document.createTextNode(entry.emoji));
 | 
				
			||||||
					list.appendChild(emoji);
 | 
										list.appendChild(emoji);
 | 
				
			||||||
					any = true;
 | 
										any = true;
 | 
				
			||||||
 | 
										any_at_all = true;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if (!any) {
 | 
									if (!any) {
 | 
				
			||||||
					list.removeChild(header);
 | 
										list.removeChild(header);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 | 
								if (!any_at_all) {
 | 
				
			||||||
 | 
									list.appendChild(document.createTextNode('No matches found.'));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		refresh();
 | 
							refresh();
 | 
				
			||||||
		input.oninput = refresh;
 | 
							input.oninput = refresh;
 | 
				
			||||||
@@ -81,5 +99,7 @@ export function picker(callback, anchor) {
 | 
				
			|||||||
		div.style.top = '50%';
 | 
							div.style.top = '50%';
 | 
				
			||||||
		div.style.left = '50%';
 | 
							div.style.left = '50%';
 | 
				
			||||||
		div.style.transform = 'translate(-50%, -50%)';
 | 
							div.style.transform = 'translate(-50%, -50%)';
 | 
				
			||||||
 | 
							input.focus();
 | 
				
			||||||
 | 
							window.addEventListener('keydown', key_down);
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -61,7 +61,7 @@ class TfComposeElement extends LitElement {
 | 
				
			|||||||
		preview.innerHTML = tfutils.markdown(text);
 | 
							preview.innerHTML = tfutils.markdown(text);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	convert_to_webp(buffer, type) {
 | 
						convert_to_format(buffer, type, mime_type) {
 | 
				
			||||||
		return new Promise(function(resolve, reject) {
 | 
							return new Promise(function(resolve, reject) {
 | 
				
			||||||
			let img = new Image();
 | 
								let img = new Image();
 | 
				
			||||||
			img.onload = function() {
 | 
								img.onload = function() {
 | 
				
			||||||
@@ -73,7 +73,7 @@ class TfComposeElement extends LitElement {
 | 
				
			|||||||
				canvas.height = img.height * scale;
 | 
									canvas.height = img.height * scale;
 | 
				
			||||||
				let context = canvas.getContext('2d');
 | 
									let context = canvas.getContext('2d');
 | 
				
			||||||
				context.drawImage(img, 0, 0, canvas.width, canvas.height);
 | 
									context.drawImage(img, 0, 0, canvas.width, canvas.height);
 | 
				
			||||||
				let data_url = canvas.toDataURL('image/webp');
 | 
									let data_url = canvas.toDataURL(mime_type);
 | 
				
			||||||
				let result = atob(data_url.split(',')[1]).split('').map(x => x.charCodeAt(0));
 | 
									let result = atob(data_url.split(',')[1]).split('').map(x => x.charCodeAt(0));
 | 
				
			||||||
				resolve(result);
 | 
									resolve(result);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -92,8 +92,18 @@ class TfComposeElement extends LitElement {
 | 
				
			|||||||
			let buffer = await file.arrayBuffer();
 | 
								let buffer = await file.arrayBuffer();
 | 
				
			||||||
			let type = file.type;
 | 
								let type = file.type;
 | 
				
			||||||
			if (type.startsWith('image/')) {
 | 
								if (type.startsWith('image/')) {
 | 
				
			||||||
				buffer = await self.convert_to_webp(buffer, file.type);
 | 
									let best_buffer;
 | 
				
			||||||
				type = 'image/webp';
 | 
									let best_type;
 | 
				
			||||||
 | 
									for (let format of ['image/png', 'image/jpeg']) {
 | 
				
			||||||
 | 
										let test_buffer = await self.convert_to_format(buffer, file.type, format);
 | 
				
			||||||
 | 
										console.log(format, test_buffer.length);
 | 
				
			||||||
 | 
										if (!best_buffer || test_buffer.length < best_buffer.length) {
 | 
				
			||||||
 | 
											best_buffer = test_buffer;
 | 
				
			||||||
 | 
											best_type = format;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									buffer = best_buffer;
 | 
				
			||||||
 | 
									type = best_type;
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				buffer = Array.from(new Uint8Array(buffer));
 | 
									buffer = Array.from(new Uint8Array(buffer));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user