Been a while since I exported these apps.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3880 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
		@@ -1 +1 @@
 | 
			
		||||
{"type":"tildefriends-app","files":{"app.js":"&C82YfV2CQsreGCcY0FHR4owqVOaN10yvVW7OZxFC8sE=.sha256"}}
 | 
			
		||||
{"type":"tildefriends-app","files":{"app.js":"&OMzy1V2Z53ARpvUnFZ1BxsQr/Z8oQmFC678s/Hh6Gtc=.sha256"}}
 | 
			
		||||
@@ -12,7 +12,7 @@ async function main() {
 | 
			
		||||
<script>
 | 
			
		||||
	function populate_apps(id, name, apps) {
 | 
			
		||||
		var list = document.getElementById(id);
 | 
			
		||||
		for (let app of Object.keys(apps)) {
 | 
			
		||||
		for (let app of Object.keys(apps).sort()) {
 | 
			
		||||
			var li = list.appendChild(document.createElement('li'));
 | 
			
		||||
			var a = document.createElement('a');
 | 
			
		||||
			a.innerText = app;
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1 @@
 | 
			
		||||
{"type":"tildefriends-app","files":{"app.js":"&5rHyeAQKxrbvIm32W3rKrh+LVRxlqLkN2cStJf5tCSM=.sha256","index.md":"&5EeOHUkDadC+lJsDsKXbfrVDQdePyOHZ7KwaJtR5mrs=.sha256","todo.md":"&uQuym9MPT7fIym79K8e/gdi5yOJrMoetZcutcsWYhQY=.sha256","structure.md":"&T+CBfT9XP6ooKFvD1ZCI9hsutqsNIamfBxtAho0HtlU=.sha256","guide.md":"&SgnGL0+rjetY2o9A2+lVRbNvHIkqKwMnZr9gXWneIlc=.sha256","id_refactor.md":"&8yoYd14gX2Z3ppktVrPYf4qR78fuwAlvrtsWkSCkWUA=.sha256"}}
 | 
			
		||||
{"type":"tildefriends-app","files":{"app.js":"&rLwYqurncmnUyGeWY+FLEGS2EIJmqw2cutl1gyGiVSk=.sha256","index.md":"&082vPjenwI6mL2vXwQDVEFquyl2jW9t767sGuCFvVNA=.sha256","todo.md":"&nr1x4grS+0J2OirgKs2dpsElUC2yTQwO6BmgiZ/Qb4w=.sha256","structure.md":"&T+CBfT9XP6ooKFvD1ZCI9hsutqsNIamfBxtAho0HtlU=.sha256","guide.md":"&SgnGL0+rjetY2o9A2+lVRbNvHIkqKwMnZr9gXWneIlc=.sha256","id_refactor.md":"&8yoYd14gX2Z3ppktVrPYf4qR78fuwAlvrtsWkSCkWUA=.sha256","ssb.md":"&049VbbMMJv9lZiKjhVhWJzSXRxV5m1QrEkYnDaoUYU8=.sha256"}}
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -5,6 +5,7 @@ network, [Secure Scuttlebutt](https://scuttlebutt.nz/),
 | 
			
		||||
augmenting it with a way to safely and securely write, share,
 | 
			
		||||
and run code.
 | 
			
		||||
 | 
			
		||||
- [Secure Scuttlebutt from Scratch](#ssb)
 | 
			
		||||
- [Structure](#structure)
 | 
			
		||||
- [Guide](#guide)
 | 
			
		||||
- [TODO](#todo)
 | 
			
		||||
 
 | 
			
		||||
@@ -22,11 +22,9 @@
 | 
			
		||||
- no denial of service
 | 
			
		||||
- expose loads of stats
 | 
			
		||||
- package standalone executable
 | 
			
		||||
- build for windows
 | 
			
		||||
- make a better connections API
 | 
			
		||||
- tf account timeout why
 | 
			
		||||
- attribute blob wants to messages
 | 
			
		||||
- installable apps (bring back an app message?)
 | 
			
		||||
- editor without app iframe
 | 
			
		||||
 | 
			
		||||
## Maybe Done
 | 
			
		||||
@@ -35,6 +33,8 @@
 | 
			
		||||
- leaking imports / exports
 | 
			
		||||
- file upload widget
 | 
			
		||||
- keep working on good error feedback
 | 
			
		||||
- build for windows
 | 
			
		||||
- installable apps (bring back an app message?)
 | 
			
		||||
 | 
			
		||||
## Done
 | 
			
		||||
- update LICENSE
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1 @@
 | 
			
		||||
{"type":"tildefriends-app","files":{"app.js":"&j8ONkf2VtLJ2+MCvwTd0hCOl074G1XFAHcJuZCxmN0k=.sha256","index.html":"&oAZVhNbqs9mLhgZj6VLgRvmCYuiGjp9D+ZH3vFV/ViM=.sha256","vue-material.js":"&K5cdLqXYCENPak/TCINHQhyJhpS4G9DlZHGwoh/LF2g=.sha256","tf-user.js":"&BwircO1usZwNmgxReG3COtztqg6bVYnVenTKsLhOeLI=.sha256","tf-message.js":"&TcKxV+QGU2LQ+yLtZbD1xdWfDSAPLRj47fBaydho3ts=.sha256","tf.js":"&ih5SgLokhC5wnL7VNnFhSD/t2mqs5gTFzUUFWBlMp3k=.sha256","commonmark.min.js":"&EP0OeR9zyLwZannz+0ga4s9AGES2RLvvIIQYHqqV6+k=.sha256","vue.js":"&g1wvA+yHl1sVC+eufTsg9If7ZeVyMTBU+h0tks7ZNzE=.sha256","vue-material-theme-default-dark.css":"&RP2nr+2CR18BpHHw5ST9a5GJUCOG9n0G2kuGkcQioWE=.sha256","vue-material.min.css":"&kGbUM2QgFSyHZRzqQb0b+0S3EVIlZ0AXpdiAVjIhou8=.sha256","roboto.css":"&jJv43Om673mQO5JK0jj7714s5E+5Yrf82H6LcDx7wUs=.sha256","material-icons.css":"&a28PdcVvgq/DxyIvJAx/e+ZOEtOuHnr3kjLWKyzH11M=.sha256","tf-shared.js":"&g17mCj0bfk0tw0sYk2VMU67Bt8Hdznjl44E01TxQF5Y=.sha256"}}
 | 
			
		||||
{"type":"tildefriends-app","files":{"app.js":"&/KEl8MyPA3758dy9OHuLWMsU7PCbrxWm8B2Lp6D6VdA=.sha256","index.html":"&1A20L0gv3iOk6hqTdxrRX3yM1jNnUlSn9+NOC+HMBSk=.sha256","vue-material.js":"&K5cdLqXYCENPak/TCINHQhyJhpS4G9DlZHGwoh/LF2g=.sha256","tf-user.js":"&BwircO1usZwNmgxReG3COtztqg6bVYnVenTKsLhOeLI=.sha256","tf-message.js":"&zSiMRlC4W91U/D+NK4O/COiDsdp0v3UH7w/ImQbjX7w=.sha256","tf.js":"&iy81728sf718+imn/XrU+T3zjJKbbuo+tlFU7wubrcw=.sha256","commonmark.min.js":"&EP0OeR9zyLwZannz+0ga4s9AGES2RLvvIIQYHqqV6+k=.sha256","vue.js":"&g1wvA+yHl1sVC+eufTsg9If7ZeVyMTBU+h0tks7ZNzE=.sha256","vue-material-theme-default-dark.css":"&RP2nr+2CR18BpHHw5ST9a5GJUCOG9n0G2kuGkcQioWE=.sha256","vue-material.min.css":"&kGbUM2QgFSyHZRzqQb0b+0S3EVIlZ0AXpdiAVjIhou8=.sha256","roboto.css":"&jJv43Om673mQO5JK0jj7714s5E+5Yrf82H6LcDx7wUs=.sha256","material-icons.css":"&a28PdcVvgq/DxyIvJAx/e+ZOEtOuHnr3kjLWKyzH11M=.sha256","tf-shared.js":"&g17mCj0bfk0tw0sYk2VMU67Bt8Hdznjl44E01TxQF5Y=.sha256","style.css":"&qegBNCrVUihxffRUxGFuG/6u+0Y6d18zHtfNHBZtZ04=.sha256"}}
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
const k_posts_max = 20;
 | 
			
		||||
const k_posts_max = 40;
 | 
			
		||||
const k_votes_max = 20;
 | 
			
		||||
 | 
			
		||||
var g_ready = false;
 | 
			
		||||
@@ -260,6 +260,9 @@ async function getRecentPostIds(db, id, ids, limit) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function getRecentPostIds2(db, id, ids, start_time) {
 | 
			
		||||
	if (ids.length == 1) {
 | 
			
		||||
		return getRecentPostsSingleId(db, ids[0], 20);
 | 
			
		||||
	}
 | 
			
		||||
	const k_batch_max = 32;
 | 
			
		||||
	var row_id_max = 0;
 | 
			
		||||
	await ssb.sqlStream(
 | 
			
		||||
@@ -281,7 +284,7 @@ async function getRecentPostIds2(db, id, ids, start_time) {
 | 
			
		||||
			"  timestamp > ? AND "+
 | 
			
		||||
			"  rowid <= ? AND "+
 | 
			
		||||
			"  json_extract(content, '$.type') = 'post' "+
 | 
			
		||||
			"ORDER BY timestamp",
 | 
			
		||||
			"ORDER BY timestamp DESC",
 | 
			
		||||
			[].concat(ids_batch, [start_time, row_id_max]),
 | 
			
		||||
			function(row) {
 | 
			
		||||
				if (row.id) {
 | 
			
		||||
@@ -500,6 +503,16 @@ async function refresh(selected) {
 | 
			
		||||
		await app.postMessage({votes: votes});
 | 
			
		||||
	}
 | 
			
		||||
	timing.push({name: 'votes', time: new Date()});
 | 
			
		||||
	if (selected && selected.length == 1 && selected[0].startsWith('@')) {
 | 
			
		||||
		let size = 0;
 | 
			
		||||
		await ssb.sqlStream(
 | 
			
		||||
			'SELECT SUM(LENGTH(content)) AS length FROM messages WHERE author = ?1',
 | 
			
		||||
			selected,
 | 
			
		||||
			function(row) {
 | 
			
		||||
				size = row.length;
 | 
			
		||||
			});
 | 
			
		||||
		await app.postMessage({user: {user: selected[0], about: {size: size}}});
 | 
			
		||||
	}
 | 
			
		||||
	await all_followed.map(
 | 
			
		||||
		id => app.postMessage(
 | 
			
		||||
			{
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
		<link rel="stylesheet" href="material-icons.css">
 | 
			
		||||
		<link rel="stylesheet" href="vue-material.min.css">
 | 
			
		||||
		<link rel="stylesheet" href="vue-material-theme-default-dark.css">
 | 
			
		||||
		<link rel="stylesheet" href="style.css">
 | 
			
		||||
		<script src="vue.js"></script>
 | 
			
		||||
		<script src="vue-material.js"></script>
 | 
			
		||||
		<script src="commonmark.min.js"></script>
 | 
			
		||||
@@ -34,29 +35,30 @@
 | 
			
		||||
					<span class="md-title">Tilde Scuttlebutt</span>
 | 
			
		||||
				</md-app-toolbar>
 | 
			
		||||
				<md-app-content>
 | 
			
		||||
					<div class="md-layout">
 | 
			
		||||
						<div class="md-layout-item md-size-20">
 | 
			
		||||
							<md-list>
 | 
			
		||||
								<md-subheader>Broadcasts</md-subheader>
 | 
			
		||||
								<md-list-item v-for="broadcast in broadcasts" v-bind:key="JSON.stringify(broadcast)" @click="ssb_connect(broadcast)">{{broadcast.address}}:{{broadcast.port}} <tf-user :id="broadcast.pubkey"></tf-user></md-list-item>
 | 
			
		||||
								<md-subheader>Connections</md-subheader>
 | 
			
		||||
								<md-list-item v-for="connection in connections" v-bind:key="'connection-' + JSON.stringify(connection)"><tf-user :id="connection"></tf-user></md-list-item>
 | 
			
		||||
								<md-list-item @click="show_connect_dialog = true">Connect</md-list-item>
 | 
			
		||||
							</md-list>
 | 
			
		||||
						</div>
 | 
			
		||||
						<div class="md-layout-item md-size-80">
 | 
			
		||||
					<md-tabs>
 | 
			
		||||
						<md-tab md-label="News">
 | 
			
		||||
							<md-app-toolbar class="md-secondary" v-show="unread > 0">
 | 
			
		||||
								<md-button @click="refresh()" class="md-raised md-primary">Refresh</md-button>
 | 
			
		||||
								<span class="md-title">{{unread}} unread item{{unread == 1 ? '' : 's'}}</span>
 | 
			
		||||
							</md-app-toolbar>
 | 
			
		||||
							Welcome, <tf-user :id="whoami"></tf-user>.
 | 
			
		||||
							<span v-if="load_time" style="float: right">
 | 
			
		||||
								Loaded in {{load_time}} seconds.
 | 
			
		||||
								<md-tooltip v-if="Object.keys(times).length" style="height: auto">
 | 
			
		||||
									<div v-for="key in Object.keys(times)">{{key}}: {{times[key]}}</div>
 | 
			
		||||
								</md-tooltip>
 | 
			
		||||
							</span>
 | 
			
		||||
							<md-card class="md-elevation-8">
 | 
			
		||||
							<md-app class="md-elevation-8">
 | 
			
		||||
								<md-app-toolbar>
 | 
			
		||||
									<div>Welcome, <tf-user :id="whoami"></tf-user>.</div>
 | 
			
		||||
								</md-app-toolbar>
 | 
			
		||||
								<md-app-content>
 | 
			
		||||
									<span v-if="load_time">
 | 
			
		||||
										Loaded in {{load_time}} seconds.
 | 
			
		||||
										<md-tooltip v-if="Object.keys(times).length" style="height: auto">
 | 
			
		||||
											<div v-for="key in Object.keys(times)">{{key}}: {{times[key]}}</div>
 | 
			
		||||
										</md-tooltip>
 | 
			
		||||
									</span>
 | 
			
		||||
									<span v-else>
 | 
			
		||||
										Loading...
 | 
			
		||||
									</span>
 | 
			
		||||
								</md-app-content>
 | 
			
		||||
							</md-app>
 | 
			
		||||
 | 
			
		||||
							<md-card class="md-elevation-8" style="margin: 1em">
 | 
			
		||||
								<md-card-header>
 | 
			
		||||
									<div class="md-title">What's up?</div>
 | 
			
		||||
								</md-card-header>
 | 
			
		||||
@@ -123,6 +125,7 @@
 | 
			
		||||
										</md-field>
 | 
			
		||||
									</div>
 | 
			
		||||
									<template v-if="users[selected]">
 | 
			
		||||
										<div>Total Message Size: {{human_size(users[selected].size)}}</div>
 | 
			
		||||
										<div v-if="users[selected].name">{{selected}}</div>
 | 
			
		||||
										<div v-html="markdown(users[selected].description)"></div>
 | 
			
		||||
									</template>
 | 
			
		||||
@@ -154,7 +157,6 @@
 | 
			
		||||
									</md-card-actions>
 | 
			
		||||
								</md-card-content>
 | 
			
		||||
							</md-card>
 | 
			
		||||
 | 
			
		||||
							<template v-if="messages.length">
 | 
			
		||||
								<tf-message
 | 
			
		||||
											v-for="message in messages"
 | 
			
		||||
@@ -167,8 +169,17 @@
 | 
			
		||||
								<md-progress-spinner md-mode="indeterminate"></md-progress-spinner>
 | 
			
		||||
							</md-empty-state>
 | 
			
		||||
							<md-empty-state v-else md-label="Nothing to see here."></md-empty-state>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
						</md-tab>
 | 
			
		||||
						<md-tab md-label="Network">
 | 
			
		||||
							<md-list>
 | 
			
		||||
								<md-subheader>Broadcasts</md-subheader>
 | 
			
		||||
								<md-list-item v-for="broadcast in broadcasts" v-bind:key="JSON.stringify(broadcast)" @click="ssb_connect(broadcast)">{{broadcast.address}}:{{broadcast.port}} <tf-user :id="broadcast.pubkey"></tf-user></md-list-item>
 | 
			
		||||
								<md-subheader>Connections</md-subheader>
 | 
			
		||||
								<md-list-item v-for="connection in connections" v-bind:key="'connection-' + JSON.stringify(connection)"><tf-user :id="connection"></tf-user></md-list-item>
 | 
			
		||||
								<md-list-item @click="show_connect_dialog = true">Connect</md-list-item>
 | 
			
		||||
							</md-list>
 | 
			
		||||
						</md-tab>
 | 
			
		||||
					</md-tabs>
 | 
			
		||||
				</md-app-content>
 | 
			
		||||
			</md-app>
 | 
			
		||||
		</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -126,6 +126,9 @@ Vue.component('tf-message', {
 | 
			
		||||
				<div v-html="this.markdown(content_json.text)"></div>
 | 
			
		||||
				<span v-for="mention in content_json.mentions" v-if="mention.link && typeof(mention.link) == 'string' && mention.link.startsWith('&')">
 | 
			
		||||
					<a v-if="mention.type == 'application/tildefriends'" :href="'/' + mention.link + '/'" target="_top">{{mention.name}}</a>
 | 
			
		||||
					<audio v-else-if="mention.name && mention.name.startsWith('audio:')" controls>
 | 
			
		||||
						<source :src="'/' + mention.link + '/view'"></source>
 | 
			
		||||
					</audio>
 | 
			
		||||
					<img v-else class="md-elevation-4" style="margin: 4px; max-width: 320px; max-height: 240px" :src="'/' + mention.link + '/view'" v-on:click="expand_image"></img>
 | 
			
		||||
				</span>
 | 
			
		||||
			</div>
 | 
			
		||||
@@ -143,7 +146,7 @@ Vue.component('tf-message', {
 | 
			
		||||
	<tf-message v-for="sub_message in (message.children || [])" v-bind:message="sub_message" v-bind:messages="messages" v-bind:votes="votes" v-bind:key="sub_message.id"></tf-message>
 | 
			
		||||
	<md-chip md-clickable v-for="v in Object.keys(votes[message.id] || {})" v-bind:key="v" @click="vote">
 | 
			
		||||
		{{v + (votes[message.id][v].length > 1 ? ' (' + votes[message.id][v].length + ')' : '')}}
 | 
			
		||||
		<md-tooltip style="height: auto">
 | 
			
		||||
		<md-tooltip style="height: auto; background-color: #000; border: 1px solid #fff">
 | 
			
		||||
			<tf-user v-for="vote in votes[message.id][v]" :id="vote.author" :key="vote.author"></tf-user>
 | 
			
		||||
		</md-tooltip>
 | 
			
		||||
	</md-chip>
 | 
			
		||||
 
 | 
			
		||||
@@ -305,6 +305,22 @@ window.addEventListener('load', function() {
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			human_size(bytes) {
 | 
			
		||||
				if (typeof bytes == 'number') {
 | 
			
		||||
					let value = bytes;
 | 
			
		||||
					let unit = 'B';
 | 
			
		||||
					const k_units = ['kB', 'MB', 'GB', 'TB'];
 | 
			
		||||
					for (let u of k_units) {
 | 
			
		||||
						if (value > 1024) {
 | 
			
		||||
							value /= 1024;
 | 
			
		||||
							unit = u;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					return Math.round(value * 10) / 10 + ' ' + unit;
 | 
			
		||||
				} else {
 | 
			
		||||
					return bytes;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user