summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/chat.js65
-rw-r--r--components/comment.js71
-rw-r--r--components/like-button.js36
-rw-r--r--components/moderation.js63
-rw-r--r--components/name.js56
-rw-r--r--components/private-messaging.js66
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>`
+}