diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/chat.js | 65 | ||||
-rw-r--r-- | components/comment.js | 71 | ||||
-rw-r--r-- | components/like-button.js | 36 | ||||
-rw-r--r-- | components/moderation.js | 63 | ||||
-rw-r--r-- | components/name.js | 56 | ||||
-rw-r--r-- | components/private-messaging.js | 66 |
6 files changed, 357 insertions, 0 deletions
diff --git a/components/chat.js b/components/chat.js new file mode 100644 index 0000000..5095dcd --- /dev/null +++ b/components/chat.js @@ -0,0 +1,65 @@ +import { Name } from './name.js' +import Comments from './comment.js' + +export default { + + components: { Name, Comments }, + + data: ()=> ({ + message: '', + channel: 'demo' + }), + + methods: { + messageObjects(objects) { + return objects.filter(o=> + 'message' in o && + 'timestamp' in o && + typeof o.message == 'string' && + typeof o.timestamp == 'number') + .sortBy('timestamp') + }, + + sendMessage() { + if (!this.message) return + this.$graffitiUpdate({ + message: this.message, + timestamp: Date.now(), + _tags: [this.channel] + }) + this.message = '' + } + }, + + template: ` + <p> + Chat Channel: <input v-model="channel"/> + </p> + + <graffiti-objects :tags="[channel]" v-slot="{objects}"> + <ul v-for="object in messageObjects(objects)"> + <li> + <em><Name :of="object._by"/></em>: + {{ object.message }} + + <Comments :messageID="object._id" /> + + <template v-if="object._by==$graffitiMyID"> + <button @click="object.message+='!!'"> + ‼️ + </button> + + <button @click="delete object._key"> + ❌ + </button> + </template> + </li> + </ul> + </graffiti-objects> + + <form @submit.prevent="sendMessage"> + <input v-model="message"> + <input type="submit" value="Submit"/> + </form>` +} + diff --git a/components/comment.js b/components/comment.js new file mode 100644 index 0000000..d838ee1 --- /dev/null +++ b/components/comment.js @@ -0,0 +1,71 @@ +import LikeButton from './like-button.js' + +export default { + name: 'Comments', + + components: { LikeButton }, + + props: ['messageID'], + + methods: { + commentObjects(objects) { + console.log(111111111111) + console.log(objects.filter(o=>'like' in o)) + console.log(objects.filter(o=>'comment' in o)) + return objects.filter(o=> + 'comment' in o && + 'timestamp' in o && + o.comment == this.messageID && + typeof o.timestamp == 'number') + .sort((a,b)=> + objects.filter(o=> + 'like' in o && + o.like == a._id).length + < objects.filter(o=> + 'like' in o && + o.like == b._id).length + ) + }, + + sendComment(objects) { + this.$graffitiUpdate({ + comment: this.messageID, + timestamp: Date.now(), + message: this.message, + _tags: [this.messageID] + }) + } + }, + + template: ` + <graffiti-objects :tags="[messageID]" v-slot="{objects}"> + <details> + <summary>Comment</summary> + <form @submit.prevent="sendComment(objects)"> + <input v-model="message"> + <input type="submit" value="Submit"/> + </form> + </details> + <details open> + <summary>Collapse thread</summary> + <ul v-for="object in commentObjects(objects)"> + <li> + <Name :of="object._by"/> + {{ object.message }} + <LikeButton :messageID="object._id" :parent="messageID"/> + <template v-if="object._by==$graffitiMyID"> + <button @click="object.message+='!!';object._update()"> + ‼️ + </button> + + <button @click="object.message='deleted';object._update()"> + ❌ + </button> + </template> + <Comments :messageID="object._id" /> + </li> + </ul> + </details> + </graffiti-objects>` +} + diff --git a/components/like-button.js b/components/like-button.js new file mode 100644 index 0000000..6f65ac6 --- /dev/null +++ b/components/like-button.js @@ -0,0 +1,36 @@ +export default { + + props: ['messageID', 'parent'], + + methods: { + likeObjects(objects, messageID=this.messageID) { + return objects.filter(o=> + 'like' in o && + 'timestamp' in o && + o.like == messageID && + typeof o.timestamp == 'number') + + }, + + toggleLike(objects) { + const myLikes = this.likeObjects(objects).mine + if (myLikes.length) { + myLikes.removeMine() + } else { + this.$graffitiUpdate({ + like: this.messageID, + timestamp: Date.now(), + _tags: [this.messageID, this.parent] + }) + } + } + }, + + template: ` + <graffiti-objects :tags="[messageID]" v-slot="{objects}"> + <button @click="toggleLike(objects)" :class="likeObjects(objects).mine.length?'button-primary':''"> + 👍 {{ likeObjects(objects).length }} + </button> + </graffiti-objects>` +} + diff --git a/components/moderation.js b/components/moderation.js new file mode 100644 index 0000000..5e12fb0 --- /dev/null +++ b/components/moderation.js @@ -0,0 +1,63 @@ +import Chat from './chat.js' +import LikeButton from './like-button.js' +import { Name } from './name.js' + +export default { + + data: ()=> ({ + likeThreshold: 0, + channel: 'demo', + admin: null + }), + + methods: { + messageObjects: Chat.methods.messageObjects, + likeObjects: LikeButton.methods.likeObjects, + }, + + template: ` + <p> + Chat Channel: <input v-model="channel"/> + </p> + + <graffiti-objects :tags="[channel]" v-slot="{objects}"> + + <h3>Example 1</h3> + + <p> + Only show me objects with more than <input v-model.number="likeThreshold"/> likes. + </p> + + <ul v-for="object in messageObjects(objects)"> + <graffiti-objects :tags="[object._id]" v-slot="{objects: responses}"> + <li v-if="likeObjects(responses, object._id).length >= likeThreshold"> + <em><Name :of="object._by"/></em>: + {{ object.message }} + </li> + </graffiti-objects> + </ul> + + <h3>Example 2</h3> + + <p> + Only show me objects that + <select v-model="admin"> + <option v-for="id in objects.authors" :value="id"> + <Name :of="id"> + </option> + </select> + has liked. + </p> + + <ul v-for="object in messageObjects(objects)"> + <graffiti-objects :tags="[object._id]" v-slot="{objects: responses}"> + <li v-if="likeObjects(responses, object._id).filter(o=> o._by==admin).length"> + <em><Name :of="object._by"/></em>: + {{ object.message }} + </li> + </graffiti-objects> + </ul> + + </graffiti-objects>` +} + diff --git a/components/name.js b/components/name.js new file mode 100644 index 0000000..ea44f95 --- /dev/null +++ b/components/name.js @@ -0,0 +1,56 @@ +export const Name = { + + props: ["of"], + + methods: { + name(objects) { + const nameObjects = objects + .filter(o=> + 'name' in o && + 'of' in o && + 'timestamp' in o && + typeof o.name == 'string' && + o.of == this.of && + o._by == this.of && + typeof o.timestamp == 'number') + .sortBy('-timestamp') + + return nameObjects.length? + nameObjects[0].name : 'anonymous' + } + }, + + template: ` + <graffiti-objects :tags="[of]" v-slot="{objects}"> + {{ name(objects) }} + </graffiti-objects>` +} + +export const SetMyName = { + + props: ["tags"], + + data: ()=> ({ + name: '' + }), + + methods: { + setMyName() { + this.$graffitiUpdate({ + name: this.name, + timestamp: Date.now(), + of: this.$graffitiMyID, + _tags: this.tags + }) + this.name = '' + } + }, + + template: ` + <form @submit.prevent="setMyName"> + <label for="nameBox">Change your name:</label> + <input v-model="name" id="nameBox"/> + <br> + <input type="submit" value="Submit"/> + </form>` +} diff --git a/components/private-messaging.js b/components/private-messaging.js new file mode 100644 index 0000000..61f783b --- /dev/null +++ b/components/private-messaging.js @@ -0,0 +1,66 @@ +import Chat from './chat.js' +import {Name} from './name.js' + +export default { + + data: ()=> ({ + recipient: null, + message: '' + }), + + methods: { + messageObjects: Chat.methods.messageObjects, + chatObjects(objects) { + return this.messageObjects(objects).filter(o=> + '_to' in o && o._to.length == 1) + }, + + sendMessage() { + if (!this.message) return + this.$graffitiUpdate({ + message: this.message, + timestamp: Date.now(), + _to: [this.recipient], + _tags: [this.$graffitiMyID, this.recipient] + }) + this.message = '' + } + }, + + template: ` + Send private message to: + <graffiti-objects :tags="['demo']" v-slot="{objects}"> + <select v-model="recipient"> + <option v-for="id in objects.notMine.authors" :value="id"> + <Name :of="id"> + </option> + </select> + </graffiti-objects> + + <form @submit.prevent="sendMessage"> + <input v-model="message"> + <input type="submit" value="Submit"/> + </form> + + <graffiti-objects :tags="[$graffitiMyID]" v-slot="{objects}"> + + <h3>My Outbox</h3> + + <ul v-for="object in chatObjects(objects).mine"> + <li> + To <em><Name :of="object._to[0]"/></em>: + {{ object.message }} + </li> + </ul> + + <h3>My Inbox</h3> + + <ul v-for="object in chatObjects(objects).notMine"> + <li> + From <em><Name :of="object._by"/></em>: + {{ object.message }} + </li> + </ul> + + </graffiti-objects>` +} |