From 29e10b6acdedb4d82bdc5b14fe1ddf18ef929049 Mon Sep 17 00:00:00 2001 From: Adam Procter <adamprocter@researchnot.es> Date: Sun, 1 Mar 2020 18:18:15 +0000 Subject: [PATCH] Emoji reaction version 1 added the ability to add emoji reactions to other nodes. Still a little messy --- app/package.json | 13 ++- app/src/components/NodesLayer.vue | 7 +- app/src/components/OtherNodeslayer.vue | 148 ++++++++++++++++++++++++- app/src/store/index.js | 51 +++++++++ app/yarn.lock | 74 +++++++------ 5 files changed, 249 insertions(+), 44 deletions(-) diff --git a/app/package.json b/app/package.json index f03c165..d02c201 100644 --- a/app/package.json +++ b/app/package.json @@ -15,15 +15,16 @@ "vue": "^2.6.11", "vue-context": "^5.0.0", "vue-draggable-resizable": "^2.1.0", - "vue-router": "^3.1.5", + "vue-emoji-picker": "^1.0.1", + "vue-router": "^3.1.6", "vuex": "^3.1.2" }, "devDependencies": { - "@vue/cli-plugin-babel": "^4.2.0", - "@vue/cli-plugin-eslint": "^4.2.0", - "@vue/cli-plugin-router": "^4.2.0", - "@vue/cli-plugin-vuex": "^4.2.0", - "@vue/cli-service": "^4.2.0", + "@vue/cli-plugin-babel": "^4.2.3", + "@vue/cli-plugin-eslint": "^4.2.3", + "@vue/cli-plugin-router": "^4.2.3", + "@vue/cli-plugin-vuex": "^4.2.3", + "@vue/cli-service": "^4.2.3", "@vue/eslint-config-prettier": "^6.0.0", "babel-eslint": "^10.0.3", "eslint": "^6.7.2", diff --git a/app/src/components/NodesLayer.vue b/app/src/components/NodesLayer.vue index 0c89324..ed33a22 100644 --- a/app/src/components/NodesLayer.vue +++ b/app/src/components/NodesLayer.vue @@ -24,6 +24,10 @@ :id="nodeid" ></textarea> </div> + <h3>Reactions</h3> + <div v-for="(emojis, index) in configEmoji" :key="index"> + <p class="allemoji" v-if="nodeid == emojis.docid">{{ emojis.emojitext }}</p> + </div> <!-- <div v-for="(value, index) in configPositions" v-bind:key="index"> <p v-if="nodeid == value.nodeid"> {{ localx }}, ({{ value.xpos }}) {{ localy }} @@ -66,7 +70,8 @@ export default { }, computed: mapState({ myNodes: state => state.myNodes, - configPositions: state => state.configPositions + configPositions: state => state.configPositions, + configEmoji: state => state.configEmoji }), methods: { onActivated() { diff --git a/app/src/components/OtherNodeslayer.vue b/app/src/components/OtherNodeslayer.vue index 3c17b1b..4ebb566 100644 --- a/app/src/components/OtherNodeslayer.vue +++ b/app/src/components/OtherNodeslayer.vue @@ -15,6 +15,57 @@ style="border: 1px solid black; background-color: rgb(205, 234, 255);" > <p :id="nodeid" :inner-html.prop="nodetext | marked">{{ nodeid }}</p> + <h3>Reactions</h3> + <div v-for="(emojis, index) in configEmoji" :key="index"> + <p class="allemoji" v-if="nodeid == emojis.docid">{{ emojis.emojitext }}</p> + </div> + <div class="react" v-if="nodeid != undefined"> + <h2>React</h2> + <div class="eeee"> + <input :value="nodeid" name="id" readonly hidden /> + <input id="emojifield" class="regular-input" v-model="input" readonly /> + + <emoji-picker @emoji="append" :search="search"> + <div + class="emoji-invoker" + slot="emoji-invoker" + slot-scope="{ events: { click: clickEvent } }" + @click.stop="clickEvent" + > + <svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"> + <path d="M0 0h24v24H0z" fill="none" /> + <path + d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5 7.67 11 8.5 11zm3.5 6.5c2.33 0 4.31-1.46 5.11-3.5H6.89c.8 2.04 2.78 3.5 5.11 3.5z" + /> + </svg> + </div> + <div slot="emoji-picker" slot-scope="{ emojis, insert, display }"> + <div + class="emoji-picker" + :style="{ top: display.y + 'px', left: display.x + 'px' }" + > + <div class="emoji-picker__search"> + <input type="text" v-model="search" v-focus /> + </div> + <div> + <div v-for="(emojiGroup, category) in emojis" :key="category"> + <h5>{{ category }}</h5> + <div class="emojis"> + <span + v-for="(emoji, emojiName) in emojiGroup" + :key="emojiName" + @click="insert(emoji)" + :title="emojiName" + >{{ emoji }}</span> + </div> + </div> + </div> + </div> + </div> + </emoji-picker> + <button @click="sentReact()">Send Reaction</button> + </div> + </div> </vue-draggable-resizable> </div> </div> @@ -22,11 +73,15 @@ <script> import { mapState } from 'vuex' +import EmojiPicker from 'vue-emoji-picker' import marked from 'marked' export default { name: 'otherNodeslayer', + components: { + EmojiPicker + }, props: { nodeid: String, nodetext: String, @@ -40,7 +95,9 @@ export default { width: this.nodewidth, height: this.nodeheight, localx: 0, - localy: 0 + localy: 0, + input: '', + search: '' } }, @@ -51,7 +108,8 @@ export default { mounted() {}, computed: mapState({ otherNodes: state => state.otherNodes, - configPositions: state => state.configPositions + configPositions: state => state.configPositions, + configEmoji: state => state.configEmoji }), methods: { onActivated() { @@ -98,6 +156,26 @@ export default { } } this.$store.dispatch('movePos', { localnodeid, x, y, width, height }) + }, + append(emoji) { + this.input += emoji + }, + sentReact(docid, emojitext) { + emojitext = this.input + docid = this.nodeid + this.$store.dispatch('addEmoji', { + docid, + emojitext + }) + + this.input = '' + } + }, + directives: { + focus: { + inserted(el) { + el.focus() + } } } } @@ -109,4 +187,70 @@ export default { background-color: aquamarine; position: absolute; } + +.emoji-invoker { + top: -0.5rem; + right: 0.5rem; + width: 1.5rem; + height: 1.5rem; + margin-top: 1em; + border-radius: 50%; + cursor: pointer; + transition: all 0.2s; +} +.emoji-invoker:hover { + transform: scale(1.1); +} +.emoji-invoker > svg { + fill: #b1c6d0; +} + +.emoji-picker { + z-index: 1; + font-family: Montserrat; + border: 1px solid #ccc; + width: 18rem; + height: 20rem; + overflow: scroll; + padding: 1rem; + box-sizing: border-box; + border-radius: 0.5rem; + background: #fff; + box-shadow: 1px 1px 8px #c7dbe6; +} +.emoji-picker__search { + display: flex; +} +.emoji-picker__search > input { + flex: 1; + border-radius: 10rem; + border: 1px solid #ccc; + padding: 0.5rem 1rem; + outline: none; +} +.emoji-picker h5 { + margin-bottom: 0; + color: #b1b1b1; + text-transform: uppercase; + font-size: 0.8rem; + cursor: default; +} +.emoji-picker .emojis { + display: flex; + flex-wrap: wrap; + justify-content: space-between; +} +.emoji-picker .emojis:after { + content: ''; + flex: auto; +} +.emoji-picker .emojis span { + padding: 0.2rem; + cursor: pointer; + border-radius: 5px; +} +.emoji-picker .emojis span:hover { + background: #ececec; + cursor: pointer; +} </style> diff --git a/app/src/store/index.js b/app/src/store/index.js index a491a8f..81fa567 100644 --- a/app/src/store/index.js +++ b/app/src/store/index.js @@ -359,14 +359,58 @@ const store = new Vuex.Store({ // pouchdb.put({ }) } }) + }, + GET_EMOJI(state) { + console.log + pouchdb + .get(state.global_emoji_name) + .then(function(doc) { + state.configEmoji = doc.emojis + }) + .catch(function(err) { + console.log(err) + if (err.status == 404) { + return pouchdb.put({ + _id: state.global_emoji_name, + emojis: [] + }) + } + }) + }, + ADD_EMOJI(state, e) { + var uniqueid = + Math.random() + .toString(36) + .substring(2, 15) + + Math.random() + .toString(36) + .substring(2, 15) + pouchdb.get(state.global_emoji_name).then(function(doc) { + doc.emojis.push({ + id: uniqueid, + docid: e.docid, + emojitext: e.emojitext + }) + return pouchdb + .put({ + _id: state.global_emoji_name, + _rev: doc._rev, + emojis: doc.emojis + }) + .catch(function(err) { + console.log(err) + }) + }) } }, + actions: { syncDB: () => { pouchdb.replicate.from(remote).on('complete', function() { store.commit('GET_ALL_NODES') store.commit('GET_MY_NODES') store.commit('GET_POSITIONS') + store.commit('GET_EMOJI') // turn on two-way, continuous, retriable sync pouchdb .sync(remote, { live: true, retry: true, attachments: true }) @@ -375,6 +419,7 @@ const store = new Vuex.Store({ store.commit('GET_ALL_NODES') store.commit('GET_MY_NODES') store.commit('GET_POSITIONS') + store.commit('GET_EMOJI') }) .on('paused', function() { // replication paused (e.g. replication up to date, user went offline) @@ -416,6 +461,12 @@ const store = new Vuex.Store({ deleteFlag: ({ commit }, e) => { // var text = e.target.value commit('DELETE_FLAG', e) + }, + addEmoji: ({ commit }, { docid, emojitext }) => { + commit('ADD_EMOJI', { + docid, + emojitext + }) } }, modules: {} diff --git a/app/yarn.lock b/app/yarn.lock index bc8b8d3..e183bd9 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -783,9 +783,9 @@ lodash.kebabcase "^4.1.1" svg-tags "^1.0.0" -"@vue/babel-preset-app@^4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@vue/babel-preset-app/-/babel-preset-app-4.2.2.tgz#c7a0a685a5eb92e1b1538f8d1fc4f5ac00dccec1" +"@vue/babel-preset-app@^4.2.3": + version "4.2.3" + resolved "https://registry.yarnpkg.com/@vue/babel-preset-app/-/babel-preset-app-4.2.3.tgz#608b2c9f7ca677e793833662fc727ff9137a9a35" dependencies: "@babel/core" "^7.8.4" "@babel/helper-compilation-targets" "^7.8.4" @@ -844,53 +844,53 @@ "@vue/babel-plugin-transform-vue-jsx" "^1.1.2" camelcase "^5.0.0" -"@vue/cli-overlay@^4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@vue/cli-overlay/-/cli-overlay-4.2.2.tgz#43184ab5b7bc491cac46e3c3e375ec4976fbea5f" +"@vue/cli-overlay@^4.2.3": + version "4.2.3" + resolved "https://registry.yarnpkg.com/@vue/cli-overlay/-/cli-overlay-4.2.3.tgz#fc26d2d48fe189e48d185910ff92433509789515" -"@vue/cli-plugin-babel@^4.2.0": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@vue/cli-plugin-babel/-/cli-plugin-babel-4.2.2.tgz#c65cad9921713b9233bab49306559c553a78ee1d" +"@vue/cli-plugin-babel@^4.2.3": + version "4.2.3" + resolved "https://registry.yarnpkg.com/@vue/cli-plugin-babel/-/cli-plugin-babel-4.2.3.tgz#8633795126f4d78c517bff9a2539229c9e0c8db4" dependencies: "@babel/core" "^7.8.4" - "@vue/babel-preset-app" "^4.2.2" - "@vue/cli-shared-utils" "^4.2.2" + "@vue/babel-preset-app" "^4.2.3" + "@vue/cli-shared-utils" "^4.2.3" babel-loader "^8.0.6" cache-loader "^4.1.0" thread-loader "^2.1.3" webpack "^4.0.0" -"@vue/cli-plugin-eslint@^4.2.0": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@vue/cli-plugin-eslint/-/cli-plugin-eslint-4.2.2.tgz#ea0ecfc3f816102f61df3050d82f23909aa3df1b" +"@vue/cli-plugin-eslint@^4.2.3": + version "4.2.3" + resolved "https://registry.yarnpkg.com/@vue/cli-plugin-eslint/-/cli-plugin-eslint-4.2.3.tgz#2a70df99aaa60697a13893e94034a1386f31c3ee" dependencies: - "@vue/cli-shared-utils" "^4.2.2" + "@vue/cli-shared-utils" "^4.2.3" eslint-loader "^2.1.2" globby "^9.2.0" inquirer "^6.3.1" webpack "^4.0.0" yorkie "^2.0.0" -"@vue/cli-plugin-router@^4.2.0", "@vue/cli-plugin-router@^4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@vue/cli-plugin-router/-/cli-plugin-router-4.2.2.tgz#2e510668341e3d2ff839a7b6a76e1250e1734223" +"@vue/cli-plugin-router@^4.2.3": + version "4.2.3" + resolved "https://registry.yarnpkg.com/@vue/cli-plugin-router/-/cli-plugin-router-4.2.3.tgz#c64594e7e7e20ba76c71262f283b6199f5afd463" dependencies: - "@vue/cli-shared-utils" "^4.2.2" + "@vue/cli-shared-utils" "^4.2.3" -"@vue/cli-plugin-vuex@^4.2.0", "@vue/cli-plugin-vuex@^4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@vue/cli-plugin-vuex/-/cli-plugin-vuex-4.2.2.tgz#f504b554e7edde945342e3c42cffad80ffa41933" +"@vue/cli-plugin-vuex@^4.2.3": + version "4.2.3" + resolved "https://registry.yarnpkg.com/@vue/cli-plugin-vuex/-/cli-plugin-vuex-4.2.3.tgz#aa1d8e824dd82b8718c0c40e3906c34ccd752516" -"@vue/cli-service@^4.2.0": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@vue/cli-service/-/cli-service-4.2.2.tgz#b2bc820a46c080a7564df23cf7e5c9592d1acc99" +"@vue/cli-service@^4.2.3": + version "4.2.3" + resolved "https://registry.yarnpkg.com/@vue/cli-service/-/cli-service-4.2.3.tgz#aabb8edfea5dbb59df5b42464f876158b43dd065" dependencies: "@intervolga/optimize-cssnano-plugin" "^1.0.5" "@soda/friendly-errors-webpack-plugin" "^1.7.1" - "@vue/cli-overlay" "^4.2.2" - "@vue/cli-plugin-router" "^4.2.2" - "@vue/cli-plugin-vuex" "^4.2.2" - "@vue/cli-shared-utils" "^4.2.2" + "@vue/cli-overlay" "^4.2.3" + "@vue/cli-plugin-router" "^4.2.3" + "@vue/cli-plugin-vuex" "^4.2.3" + "@vue/cli-shared-utils" "^4.2.3" "@vue/component-compiler-utils" "^3.0.2" "@vue/preload-webpack-plugin" "^1.1.0" "@vue/web-component-wrapper" "^1.2.0" @@ -938,9 +938,9 @@ webpack-dev-server "^3.10.2" webpack-merge "^4.2.2" -"@vue/cli-shared-utils@^4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@vue/cli-shared-utils/-/cli-shared-utils-4.2.2.tgz#953fec34115cb12d0820012a9d7400f8c27d6660" +"@vue/cli-shared-utils@^4.2.3": + version "4.2.3" + resolved "https://registry.yarnpkg.com/@vue/cli-shared-utils/-/cli-shared-utils-4.2.3.tgz#13646452cc25b0ab68a57cb52cac27983cee39a4" dependencies: "@hapi/joi" "^15.0.1" chalk "^2.4.2" @@ -7163,6 +7163,10 @@ vue-draggable-resizable@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/vue-draggable-resizable/-/vue-draggable-resizable-2.1.0.tgz#b590212aef3c07d040aeceda784438068170fb08" +vue-emoji-picker@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vue-emoji-picker/-/vue-emoji-picker-1.0.1.tgz#0c893b21fb2ac46c6b5803476d744ae3d420f98b" + vue-eslint-parser@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-7.0.0.tgz#a4ed2669f87179dedd06afdd8736acbb3a3864d6" @@ -7188,9 +7192,9 @@ vue-loader@^15.8.3: vue-hot-reload-api "^2.3.0" vue-style-loader "^4.1.0" -vue-router@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.1.5.tgz#ff29b8a1e1306c526b52d4dc0532109f16c41231" +vue-router@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.1.6.tgz#45f5a3a3843e31702c061dd829393554e4328f89" vue-style-loader@^4.1.0, vue-style-loader@^4.1.2: version "4.1.2" -- GitLab