Merge pull request #20 from Cameri/feature/add-mentionable-textarea

This commit is contained in:
fiatjaf 2022-01-30 08:18:11 -03:00 committed by GitHub
commit 390f2241c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 107 additions and 6 deletions

View File

@ -29,6 +29,7 @@
"relative-date": "^1.1.3", "relative-date": "^1.1.3",
"stream": "^0.0.2", "stream": "^0.0.2",
"tailwindcss": "^3.0.1", "tailwindcss": "^3.0.1",
"tributejs": "^5.1.3",
"vuex": "^4.0.1" "vuex": "^4.0.1"
}, },
"devDependencies": { "devDependencies": {

View File

@ -27,7 +27,11 @@ module.exports = configure(function (ctx) {
boot: ['global-components'], boot: ['global-components'],
// https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css // https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css
css: ['add-tailwind.css', '../../node_modules/highlight.js/styles/base16/solarized-light.css'], css: [
'add-tailwind.css',
'../../node_modules/highlight.js/styles/base16/solarized-light.css',
'../../node_modules/tributejs/tribute.css'
],
// https://github.com/quasarframework/quasar/tree/dev/extras // https://github.com/quasarframework/quasar/tree/dev/extras
extras: [ extras: [

View File

@ -3,6 +3,7 @@
<q-card-section> <q-card-section>
<q-form @submit="sendPost"> <q-form @submit="sendPost">
<q-input <q-input
ref="input"
v-model="text" v-model="text"
autogrow autogrow
autofocus autofocus
@ -44,9 +45,27 @@ export default {
data() { data() {
return { return {
text: '' text: '',
} }
}, },
computed: {
textarea() {
return this.$refs.input.$el.querySelector('textarea')
},
mentions() {
return this.createMentionsProvider()
}
},
mounted() {
this.mentions.attach(this.textarea)
},
beforeUnmount() {
this.mentions.detach(this.textarea)
},
methods: { methods: {
async sendPost() { async sendPost() {
if (!this.text.length) { if (!this.text.length) {

View File

@ -1,6 +1,7 @@
<template> <template>
<q-form class="px-24" @submit="sendReply"> <q-form class="px-24" @submit="sendReply">
<q-input <q-input
ref="input"
v-model="text" v-model="text"
autogrow autogrow
autofocus autofocus
@ -32,6 +33,23 @@ export default {
} }
}, },
computed: {
textarea() {
return this.$refs.input.$el.querySelector('textarea')
},
mentions() {
return this.createMentionsProvider()
}
},
mounted() {
this.mentions.attach(this.textarea)
},
beforeUnmount() {
this.mentions.detach(this.textarea)
},
methods: { methods: {
async sendReply() { async sendReply() {
if (!this.text.length) { if (!this.text.length) {

View File

@ -1,5 +1,14 @@
import Identicon from 'identicon.js' import Identicon from 'identicon.js'
export function namedProfiles(state, getters) {
return Object.entries(state.profilesCache)
.reduce((result, [pubkey, profile]) => getters.hasName(pubkey)
? [...result, { ...profile, pubkey }] // [..., { name, pubkey, nip05, ...}, ...]
: result,
[]
)
}
export function hasName(state) { export function hasName(state) {
return pubkey => { return pubkey => {
let {name, nip05} = state.profilesCache[pubkey] || {} let {name, nip05} = state.profilesCache[pubkey] || {}

View File

@ -1,3 +1,7 @@
export function shorten(str) {
return str ? str.slice(0, 3) + '…' + str.slice(-4) : ''
}
export function getElementFullHeight(element) { export function getElementFullHeight(element) {
let styles = window.getComputedStyle(element) let styles = window.getComputedStyle(element)
let margin = let margin =
@ -54,7 +58,7 @@ export function processMentions(event) {
match => match.groups.p match => match.groups.p
) )
const tags = Array.from(new Set(matches).values()).reduce( const tags = matches.reduce(
(tags, pubkey) => (tags, pubkey) =>
tags.find(([t, v]) => t === 'p' && v === pubkey) tags.find(([t, v]) => t === 'p' && v === pubkey)
? tags ? tags

View File

@ -1,5 +1,7 @@
import relative from 'relative-date' import relative from 'relative-date'
import {date} from 'quasar' import {date} from 'quasar'
import Tribute from 'tributejs'
import {shorten} from './helpers'
export default { export default {
methods: { methods: {
@ -19,9 +21,7 @@ export default {
this.$router.push('/event/' + id) this.$router.push('/event/' + id)
}, },
shorten(str) { shorten,
return str ? str.slice(0, 3) + '…' + str.slice(-4) : ''
},
niceDate(value) { niceDate(value) {
if (value + 60 * 60 /* an hour */ > Date.now() / 1000) { if (value + 60 * 60 /* an hour */ > Date.now() / 1000) {
@ -39,6 +39,47 @@ export default {
} }
return text.replace(/\B#\[(\d+)\]\B/g, replacer) return text.replace(/\B#\[(\d+)\]\B/g, replacer)
},
createMentionsProvider(options) {
const tribute = new Tribute({
spaceSelectsMatch: true,
menuShowMinLength: 1,
selectTemplate: item => `@${item.original.value.pubkey}`,
menuItemTemplate: item => {
return `
<div class="flex items-center">
<div class="inline-flex items-center">
<div class="text-secondary mr-2">${item.string}</div>
${item.original.value.nip05
? '<i class="notranslate material-icons text-accent mr-1 -ml-1" aria-hidden="true" role="presentation">verified</i>'
: ''}
</div>
<div class="text-accent font-mono text-xs">${shorten(item.original.value.pubkey)}</div>
</div>
`
},
values: (_pattern, callback) => {
callback(
this.$store.getters
.namedProfiles
.map(profile => ({
key: this.$store.getters.displayName(profile.pubkey),
value: profile,
}))
)
},
noMatchTemplate: () => undefined, // hide "No matches"
})
return {
attach: element => tribute.attach(element),
detach: element => tribute.detach(element),
}
} }
} }
} }

View File

@ -6631,6 +6631,11 @@ totalist@^1.0.0:
resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==
tributejs@^5.1.3:
version "5.1.3"
resolved "https://registry.yarnpkg.com/tributejs/-/tributejs-5.1.3.tgz#980600fc72865be5868893078b4bfde721129eae"
integrity sha512-B5CXihaVzXw+1UHhNFyAwUTMDk1EfoLP5Tj1VhD9yybZ1I8DZJEv8tZ1l0RJo0t0tk9ZhR8eG5tEsaCvRigmdQ==
trim-left-x@^3.0.0: trim-left-x@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/trim-left-x/-/trim-left-x-3.0.0.tgz#356cf055896726b9754425e841398842e90b4cdf" resolved "https://registry.yarnpkg.com/trim-left-x/-/trim-left-x-3.0.0.tgz#356cf055896726b9754425e841398842e90b4cdf"