diff --git a/CHANGELOG.md b/CHANGELOG.md index b77d9698378a70530944261d5618fd80e837adf3..902d7369fe495342fbb9fbc363e702b6cc2e3c53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# 0.2.5 + +_10th Septemeber 2021_ + +## Added + +- various formatting buttons to format your node text with markdown +- emojis "voting" is now working on other nodes + # 0.2.4 _6th Septemeber 2021_ diff --git a/package.json b/package.json index 850e2e1c37e9e1c004c14649f9f43adacfe14373..ecabccf87a04c49ac99a0430804641f3b31baff3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodenogg.in", - "version": "0.2.4", + "version": "0.2.5", "private": true, "scripts": { "serve": "vue-cli-service serve", @@ -16,6 +16,7 @@ "vue": "^3.2.8", "vue-router": "^4.0.0", "vue3-swatches": "^1.0.3", + "vuemoji-picker": "^0.0.7", "vuex": "^4.0.0" }, "devDependencies": { diff --git a/src/components/JoinMicrocosm.vue b/src/components/JoinMicrocosm.vue index 480d18b8680d2e430c4084fe3a240492451e9575..eb5b6cc621ea0d85a739ec3a7ecf26d40828d203 100644 --- a/src/components/JoinMicrocosm.vue +++ b/src/components/JoinMicrocosm.vue @@ -147,7 +147,7 @@ export default { methods: { setName(name) { - // format name so no spaces or dashes PouchDB/ CouchDB dont like them + // format name so no spaces or dashes PouchDB/ CouchDB doesn't like them var lowercasename = this.name.toLowerCase() var spacesremoved = lowercasename.split(' ').join('') this.nameFormatted = spacesremoved.split('-').join('') @@ -162,7 +162,7 @@ export default { setMicrocosm() { if (this.nameSet == true) { this.$router.push({ path: '/collect' }) - // format microcosm so no spaces or dashes PouchDB/ CouchDB dont like them + // format microcosm so no spaces or dashes PouchDB/ CouchDB doesn't like them var lowercasemicrocosm = this.microcosm.toLowerCase() var spacesremoved = lowercasemicrocosm.split(' ').join('') this.microcosmFormatted = spacesremoved.split('-').join('') diff --git a/src/components/MyNodes.vue b/src/components/MyNodes.vue index c79518e2c163dc34456f7655e16d9c54361180fa..0834db29e3a36b8230fa24650a75a31f180683b9 100644 --- a/src/components/MyNodes.vue +++ b/src/components/MyNodes.vue @@ -14,9 +14,20 @@ ref="textentry" placeholder="Type your thoughts and ideas here! (auto saved every keystroke)" rows="5" + @mouseup="getSelected($event)" ></textarea> <p class="info">*markdown supported & autosaves</p> - + <div> + <button @click.prevent="makeH1">Header 1</button> + <button @click.prevent="makeH2">Header 2</button> + <button @click.prevent="makeH3">Header 3</button> + </div> + <div> + <button @click.prevent="makeBold">Bold</button> + <button @click.prevent="makeItalic">Italic</button> + <button @click.prevent="makeLink">Link</button> + <button @click.prevent="makeImage">Image</button> + </div> <VSwatches v-model="nodes.node_color" :swatches="swatches" @@ -81,6 +92,10 @@ export default { data() { return { + nodeid: String, + start: String, + end: String, + selection: String, myArray: [], shapes: 'circles', // swatches: [{ color: '#F493A7', showBorder: true }], @@ -119,6 +134,92 @@ export default { methods: { marked, + + getSelected(e) { + this.selection = e.target.value.substring( + e.target.selectionStart, + e.target.selectionEnd + ) + this.start = e.target.selectionStart + this.end = e.target.selectionEnd + this.nodeid = e.target.id + }, + + makeH1() { + const symbol = '# ' + var text = `${symbol}${this.selection}` + var textarea = document.getElementById(this.nodeid) + textarea.setRangeText(text, this.start, this.end, 'select') + this.editNodeStyle(this.nodeid, textarea.value) + }, + + makeH2() { + const symbol = '## ' + var text = `${symbol}${this.selection}` + var textarea = document.getElementById(this.nodeid) + textarea.setRangeText(text, this.start, this.end, 'select') + this.editNodeStyle(this.nodeid, textarea.value) + }, + + makeH3() { + const symbol = '### ' + var text = `${symbol}${this.selection}` + var textarea = document.getElementById(this.nodeid) + textarea.setRangeText(text, this.start, this.end, 'select') + this.editNodeStyle(this.nodeid, textarea.value) + }, + + makeBold() { + const symbol = '**' + var text = `${symbol}${this.selection}${symbol}` + var textarea = document.getElementById(this.nodeid) + textarea.setRangeText(text, this.start, this.end, 'select') + this.editNodeStyle(this.nodeid, textarea.value) + }, + + makeItalic() { + const symbol = '*' + var text = `${symbol}${this.selection}${symbol}` + var textarea = document.getElementById(this.nodeid) + textarea.setRangeText(text, this.start, this.end, 'select') + this.editNodeStyle(this.nodeid, textarea.value) + }, + + makeLink() { + const one = '[' + const two = ']' + const three = '(' + const four = ')' + + var text = `${one}${ + this.selection + }${two}${three}${'https://urlhere'}${four}` + var textarea = document.getElementById(this.nodeid) + textarea.setRangeText(text, this.start, this.end, 'select') + this.editNodeStyle(this.nodeid, textarea.value) + var cursorplace = this.end + 3 + console.log(cursorplace) + textarea.focus() + textarea.setSelectionRange(cursorplace, cursorplace + 15) + }, + + makeImage() { + const one = '![' + const two = ']' + const three = '(' + const four = ')' + var text = `${one}${ + this.selection + }${two}${three}${'imagelinkhere'}${four}` + var textarea = document.getElementById(this.nodeid) + textarea.setRangeText(text, this.start, this.end, 'select') + this.editNodeStyle(this.nodeid, textarea.value) + var cursorplace = this.end + 4 + console.log(cursorplace) + textarea.focus() + textarea.setSelectionRange(cursorplace, cursorplace + 13) + }, + loadData() { var nodesFiltered = this.myNodes.myNodes.filter( (nodes) => nodes.node_deleted == false @@ -127,6 +228,10 @@ export default { this.myArray = nodesFiltered.reverse() }, + editNodeStyle(nodeid, nodetext) { + this.$store.dispatch('editNode', { nodeid, nodetext }) + }, + editNode(e) { var nodeid = e.target.id var nodetext = e.target.value diff --git a/src/components/OtherNodes.vue b/src/components/OtherNodes.vue index a9a696cc542a061c1b05fdf116cae25c046173a7..bc479b76c2471bc5e89a80bb5aaab4ac30dd4751 100644 --- a/src/components/OtherNodes.vue +++ b/src/components/OtherNodes.vue @@ -12,6 +12,36 @@ :id="nodes.node_id" v-html="marked(nodes.node_text)" ></p> + <div class="allemoji"> + <div + class="eachemoji" + v-for="(emojis, index) in allEmoji.allEmoji" + :key="index" + > + <p v-if="nodes.node_id == emojis.node_id"> + {{ emojis.emoji_unicode }} + </p> + </div> + </div> + <button @click="openEmoji(nodes.node_id)"> + <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> + </button> + <VuemojiPicker + v-if="showEmoji === nodes.node_id" + class="emojipicker" + @emojiClick="($event) => handleEmojiClick(nodes.node_id, $event)" + :pickerStyle="{}" + /> </div> </template> @@ -19,25 +49,76 @@ // @ is an alias to /src import { mapState } from 'vuex' import marked from 'marked' +import { VuemojiPicker } from 'vuemoji-picker' export default { name: 'OtherNodes', + props: { + // these are for the emoji styling + // https://github.com/wobsoriano/vuemoji-picker + // isDark: Boolean, + pickerStyle: Object, + }, + + data: function () { + return { + showEmoji: String, + } + }, + + components: { + VuemojiPicker, + }, + computed: { ...mapState({ otherNodes: (state) => state.otherNodes, + allEmoji: (state) => state.allEmoji, }), }, mounted() { this.$store.dispatch('getOthernodes') setTimeout(this.loadData, 500) + // this is to get the last letter typed if no space + // this also loads in new Emoji + // May need to EDIT setInterval(this.loadData, 5000) }, methods: { + getNodeid(nodeid) { + this.nodeid = nodeid + }, + handleEmojiClick(nodeid, detail) { + console.log(nodeid) + + var unicode = detail.emoji.unicode + var annotation = detail.emoji.annotation + var skinTone = detail.skinTone + var emoticon = detail.emoji.emoticon + + this.$store.dispatch('addEmoji', { + nodeid, + unicode, + annotation, + skinTone, + emoticon, + }) + }, + + openEmoji(nodeid) { + if (this.showEmoji == nodeid) { + this.showEmoji = null + } else { + this.showEmoji = nodeid + } + }, + loadData() { this.$store.dispatch('setOthernodes') + this.$store.dispatch('getEmoji') }, marked, }, @@ -48,4 +129,16 @@ export default { .nodes { border: 2px solid black; } + +button { + background: none; + border: none; +} + +.allemoji { + font-size: 1.5em; + padding: 0em; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(0, auto)); +} </style> diff --git a/src/store/modules/allEmoji.js b/src/store/modules/allEmoji.js new file mode 100644 index 0000000000000000000000000000000000000000..c55aa6b3ec830517cf041f3466057677db438152 --- /dev/null +++ b/src/store/modules/allEmoji.js @@ -0,0 +1,71 @@ +var pouchdb + +export const state = { + docName: 'emojis', + allEmoji: [], +} + +export const mutations = { + GET_EMOJI(state) { + pouchdb + .get(state.docName) + .then(function (doc) { + state.allEmoji = doc.emojis + }) + .catch(function (err) { + if (err.status == 404) { + return pouchdb.put({ + _id: state.docName, + emojis: [], + }) + } + }) + }, + ADD_EMOJI(state, e) { + var uniqueid = + Math.random().toString(36).substring(2, 15) + + Math.random().toString(36).substring(2, 15) + pouchdb.get(state.docName).then(function (doc) { + doc.emojis.push({ + emoji_id: uniqueid, + node_id: e.nodeid, + emoji_unicode: e.unicode, + emoji_annotation: e.annotation, + emoji_skintone: e.skinTone, + emoji_emoticon: e.emoticon, + }) + return pouchdb + .put({ + _id: state.docName, + _rev: doc._rev, + emojis: doc.emojis, + }) + .catch(function () {}) + }) + }, +} + +export const actions = { + getEmoji: ({ commit }) => { + commit('GET_EMOJI') + }, + + addEmoji: ( + { commit }, + { nodeid, unicode, annotation, skinTone, emoticon } + ) => { + commit('ADD_EMOJI', { + nodeid, + unicode, + annotation, + skinTone, + emoticon, + }) + }, + + getMicrocosm(vuexContext) { + pouchdb = vuexContext.rootState.setup.pouchdb + }, +} + +export const getters = {} diff --git a/src/store/modules/otherNodes.js b/src/store/modules/otherNodes.js index 4982e118c09f68fcb6c113dcace9c02e2e070bf0..a275d97fa7ad6d164395668f7c2a1f446f5fc4a4 100644 --- a/src/store/modules/otherNodes.js +++ b/src/store/modules/otherNodes.js @@ -1,5 +1,6 @@ var pouchdb var deviceName +var docName export const state = { allNodes: [], @@ -27,7 +28,10 @@ export const mutations = { var j for (i = 0; i < Object.keys(state.allNodes).length; i++) { - if (state.allNodes[i].id != deviceName) { + if ( + state.allNodes[i].id != deviceName && + state.allNodes[i].id != docName + ) { for (j = 0; j < Object.keys(state.allNodes[i].doc.nodes).length; j++) { const newNode = { node_id: state.allNodes[i].doc.nodes[j].node_id, @@ -55,6 +59,7 @@ export const actions = { getMicrocosm(vuexContext) { deviceName = vuexContext.rootState.setup.deviceName pouchdb = vuexContext.rootState.setup.pouchdb + docName = vuexContext.rootState.allEmoji.docName }, } diff --git a/src/store/store.js b/src/store/store.js index 25f199bfbfd4620245555d4d9403b5b5a8fc015b..36304dc680c73db1996359bf21d95983973472b2 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -3,6 +3,7 @@ import { createStore } from 'vuex' import * as setup from '@/store/modules/setup.js' import * as myNodes from '@/store/modules/myNodes.js' import * as otherNodes from '@/store/modules/otherNodes.js' +import * as allEmoji from '@/store/modules/allEmoji.js' export const store = createStore({ // @@ -10,6 +11,7 @@ export const store = createStore({ setup, myNodes, otherNodes, + allEmoji, }, actions: {}, diff --git a/yarn.lock b/yarn.lock index 3ec9e57d0014528d8a6906831a999fe493e0a191..a87f6a0fb6e88212e787b6874361dd3c4f27500a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3099,6 +3099,11 @@ elliptic@^6.5.3: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emoji-picker-element@^1.6.5: + version "1.8.1" + resolved "https://registry.yarnpkg.com/emoji-picker-element/-/emoji-picker-element-1.8.1.tgz#3b832b6b60b4f5543c7b7021fd9b669d2478ea44" + integrity sha512-ibliBMR74JuoPOJXGDX/RtyW1BULENfDoAY9V2mpbfcnEiqElZ9EdUrtQbwyjjHZzYS+W5nngwcI8UNNCDh6cw== + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -7632,6 +7637,11 @@ vm-browserify@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" +vue-demi@^0.11.2: + version "0.11.4" + resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.11.4.tgz#6101992fe4724cf5634018a16e953f3052e94e2a" + integrity sha512-/3xFwzSykLW2HiiLie43a+FFgNOcokbBJ+fzvFXd0r2T8MYohqvphUyDQ8lbAwzQ3Dlcrb1c9ykifGkhSIAk6A== + vue-eslint-parser@^7.10.0: version "7.10.0" resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-7.10.0.tgz#ea4e4b10fd10aa35c8a79ac783488d8abcd29be8" @@ -7697,6 +7707,14 @@ vue@^3.2.8: "@vue/runtime-dom" "3.2.8" "@vue/shared" "3.2.8" +vuemoji-picker@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/vuemoji-picker/-/vuemoji-picker-0.0.7.tgz#382d365e75644683dba0530945ed4495eaeb1708" + integrity sha512-Q0RM6qo67Px3evoY9EbEg7HzBuk+u3D+c9r4wMyU71GQQnDFKEo4ZmI7OVjonwkCyk/6C6RDpQAtGOwfahXkoA== + dependencies: + emoji-picker-element "^1.6.5" + vue-demi "^0.11.2" + vuex@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/vuex/-/vuex-4.0.2.tgz#f896dbd5bf2a0e963f00c67e9b610de749ccacc9"