logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe git clone https://hacktivis.me/git/pleroma-fe.git
commit: 22c8f71945c6d114bf4db89c87eb1b166775f2d6
parent 1923ed84d451011df42e47a85060cc754a011e27
Author: Henry Jameson <me@hjkos.com>
Date:   Mon,  7 Jun 2021 16:16:10 +0300

mention link

Diffstat:

Asrc/components/mention_link/mention_link.js71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/components/mention_link/mention_link.scss49+++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/components/mention_link/mention_link.vue17+++++++++++++++++
Msrc/components/rich_content/rich_content.jsx16+++++++++++++---
Msrc/components/status_content/status_content.js7+++++++
Msrc/modules/users.js4++++
6 files changed, 161 insertions(+), 3 deletions(-)

diff --git a/src/components/mention_link/mention_link.js b/src/components/mention_link/mention_link.js @@ -0,0 +1,71 @@ +import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' +import { getTextColor, rgb2hex } from 'src/services/color_convert/color_convert.js' +import { mapGetters, mapState } from 'vuex' +import { convert } from 'chromatism' + +const MentionLink = { + name: 'MentionLink', + props: { + url: { + required: true, + type: String + }, + content: { + required: true, + type: String + }, + origattrs: { + required: true, + type: Object + } + }, + methods: { + onClick () { + const link = generateProfileLink(this.user.id, this.user.screen_name) + this.$router.push(link) + } + }, + computed: { + user () { + return this.$store.getters.findUserByUrl(this.url) + }, + isYou () { + // FIXME why user !== currentUser??? + return this.user.screen_name === this.currentUser.screen_name + }, + userName () { + return this.userNameFullUi.split('@')[0] + }, + userNameFull () { + return this.user.screen_name + }, + userNameFullUi () { + return this.user.screen_name_ui + }, + highlight () { + return this.mergedConfig.highlight[this.user.screen_name] + }, + bg () { + if (this.highlight) return this.highlight.color + }, + text () { + if (this.bg) { + const linkColor = this.mergedConfig.customTheme.colors.link + const color = getTextColor(convert(this.bg).rgb, convert(linkColor).rgb) + return rgb2hex(color) + } + }, + style () { + return [ + this.bg && `--mention-bg: ${this.bg}`, + this.text && `--mention-text: ${this.text}` + ].filter(_ => _).join('; ') + }, + ...mapGetters(['mergedConfig']), + ...mapState({ + currentUser: state => state.users.currentUser + }) + } +} + +export default MentionLink diff --git a/src/components/mention_link/mention_link.scss b/src/components/mention_link/mention_link.scss @@ -0,0 +1,49 @@ +.MentionLink { + position: relative; + white-space: normal; + display: inline-block; + + & .new, + & .original, + & .full { + padding: 0 2px; + margin: 0 -2px; + display: inline-block; + border-radius: 2px; + } + + .original { + opacity: 0.5; + } + + .full { + pointer-events: none; + position: absolute; + opacity: 0; + top: 0; + bottom: 0; + left: 0; + word-wrap: normal; + white-space: nowrap; + transition: opacity 0.2s ease; + background-color: var(--mention-bg, var(--popover)); + color: var(--mention-text, var(--link)); + z-index: 1; + } + + .new { + background-color: var(--mention-bg); + color: var(--mention-text, var(--link)); + + &.-you { + & .shortName, + & .full { + font-weight: 600; + } + } + } + + &:hover .new .full { + opacity: 1; + } +} diff --git a/src/components/mention_link/mention_link.vue b/src/components/mention_link/mention_link.vue @@ -0,0 +1,17 @@ +<template> + <span class="MentionLink"> + <a v-if="!user" v-html="content" href="url" class="original"/> + <span v-if="user" class="new" :style="style" :class="{ '-you': isYou }" > + <button class="button-unstyled short" @click.prevent="onClick"> + <span class="shortName">@<span v-html="userName" /></span> <span v-if="isYou">(You)</span> + </button> + <span class="full" v-if="userName !== userNameFull"> + @<span v-html="userNameFull" /> + </span> + </span> + </span> +</template> + +<script src="./mention_link.js"/> + +<style lang="scss" src="./mention_link.scss"/> diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx @@ -1,7 +1,8 @@ import Vue from 'vue' -import { unescape } from 'lodash' +import { unescape, flattenDeep } from 'lodash' import { convertHtml, getTagName, processTextForEmoji, getAttrs } from 'src/services/mini_html_converter/mini_html_converter.service.js' import StillImage from 'src/components/still-image/still-image.vue' +import MentionLink from 'src/components/mention_link/mention_link.vue' import './rich_content.scss' @@ -22,6 +23,9 @@ export default Vue.component('RichContent', { const attrs = getAttrs(tag) return <StillImage {...{ attrs }} class="img"/> } + const renderMention = (attrs, children) => { + return <MentionLink url={attrs.href} content={flattenDeep(children).join('')} origattrs={attrs}/> + } const structure = convertHtml(this.html) const processItem = (item) => { if (typeof item === 'string') { @@ -45,8 +49,14 @@ export default Vue.component('RichContent', { if (Array.isArray(item)) { const [opener, children] = item const Tag = getTagName(opener) - if (Tag === 'img') { - return renderImage(opener) + switch (Tag) { + case 'img': + return renderImage(opener) + case 'a': + const attrs = getAttrs(opener) + if (attrs['class'] && attrs['class'].includes('mention')) { + return renderMention(attrs, children) + } } if (children !== undefined) { return <Tag {...{ attrs: getAttrs(opener) }}> diff --git a/src/components/status_content/status_content.js b/src/components/status_content/status_content.js @@ -168,6 +168,13 @@ const StatusContent = { LinkPreview, RichContent }, + mounted () { + const { attentions } = this.status + attentions.forEach(attn => { + const { id } = attn + this.$store.state.api.backendInteractor.fetchUserIfMissing(this.$store, id) + }) + }, methods: { linkClicked (event) { const target = event.target.closest('.status-content a') diff --git a/src/modules/users.js b/src/modules/users.js @@ -246,6 +246,10 @@ export const getters = { } return result }, + findUserByUrl: state => query => { + return state.users + .find(u => u.statusnet_profile_url.toLowerCase() === query.toLowerCase()) + }, relationship: state => id => { const rel = id && state.relationships[id] return rel || { id, loading: true }