Merge branch 'custom_reacts' into stable (edwin squirty)
This commit is contained in:
commit
2745aabcb4
8 changed files with 92 additions and 105 deletions
|
@ -1,9 +1,28 @@
|
|||
@import '../../_variables.scss';
|
||||
|
||||
.Notification {
|
||||
.emoji-picker {
|
||||
min-width: 160%;
|
||||
width: 150%;
|
||||
overflow: hidden;
|
||||
left: -70%;
|
||||
max-width: 100%;
|
||||
@media (min-width: 800px) and (max-width: 1300px) {
|
||||
left: -50%;
|
||||
min-width: 50%;
|
||||
max-width: 130%;
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
left: -10%;
|
||||
min-width: 50%;
|
||||
max-width: 130%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.emoji-picker {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
margin: 0 !important;
|
||||
|
|
|
@ -27,7 +27,11 @@ const EmojiReactions = {
|
|||
},
|
||||
accountsForEmoji () {
|
||||
return this.status.emoji_reactions.reduce((acc, reaction) => {
|
||||
acc[reaction.name] = reaction.accounts || []
|
||||
if (reaction.url) {
|
||||
acc[reaction.url] = reaction.accounts || []
|
||||
} else {
|
||||
acc[reaction.name] = reaction.accounts || []
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
},
|
||||
|
@ -42,6 +46,14 @@ const EmojiReactions = {
|
|||
reactedWith (emoji) {
|
||||
return this.status.emoji_reactions.find(r => r.name === emoji).me
|
||||
},
|
||||
isLocalReaction (emojiUrl) {
|
||||
if (!emojiUrl) return true
|
||||
const reacted = this.accountsForEmoji[emojiUrl]
|
||||
if (reacted.length === 0) {
|
||||
return true
|
||||
}
|
||||
return reacted[0].is_local
|
||||
},
|
||||
fetchEmojiReactionsByIfMissing () {
|
||||
const hasNoAccounts = this.status.emoji_reactions.find(r => !r.accounts)
|
||||
if (hasNoAccounts) {
|
||||
|
|
|
@ -2,17 +2,33 @@
|
|||
<div class="emoji-reactions">
|
||||
<UserListPopover
|
||||
v-for="(reaction) in emojiReactions"
|
||||
:key="reaction.name"
|
||||
:users="accountsForEmoji[reaction.name]"
|
||||
:key="reaction.url || reaction.name"
|
||||
:users="accountsForEmoji[reaction.url || reaction.name]"
|
||||
>
|
||||
<button
|
||||
class="emoji-reaction btn button-default"
|
||||
:class="{ 'picked-reaction': reactedWith(reaction.name), 'not-clickable': !loggedIn }"
|
||||
:disabled="!isLocalReaction(reaction.url)"
|
||||
@click="emojiOnClick(reaction.name, $event)"
|
||||
@mouseenter="fetchEmojiReactionsByIfMissing()"
|
||||
>
|
||||
<span class="reaction-emoji">{{ reaction.name }}</span>
|
||||
<span>{{ reaction.count }}</span>
|
||||
<span
|
||||
v-if="reaction.url !== null"
|
||||
>
|
||||
<img
|
||||
:src="reaction.url"
|
||||
:title="reaction.name"
|
||||
class="emoji"
|
||||
height="32px"
|
||||
>
|
||||
{{ reaction.count }}
|
||||
</span>
|
||||
<span v-else>
|
||||
<span class="reaction-emoji unicode-emoji">
|
||||
{{ reaction.name }}
|
||||
</span>
|
||||
<span>{{ reaction.count }}</span>
|
||||
</span>
|
||||
</button>
|
||||
</UserListPopover>
|
||||
<a
|
||||
|
@ -36,6 +52,10 @@
|
|||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.unicode-emoji {
|
||||
font-size: 185%;
|
||||
}
|
||||
|
||||
.emoji-reaction {
|
||||
padding: 0 0.5em;
|
||||
margin-right: 0.5em;
|
||||
|
@ -44,10 +64,6 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
.reaction-emoji {
|
||||
width: 1.25em;
|
||||
margin-right: 0.25em;
|
||||
}
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
@ -73,7 +89,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.picked-reaction {
|
||||
.button-default.picked-reaction {
|
||||
border: 1px solid var(--accent, $fallback--link);
|
||||
margin-left: -1px; // offset the border, can't use inset shadows either
|
||||
margin-right: calc(0.5em - 1px);
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
@import '../../_variables.scss';
|
||||
|
||||
.notification-reaction-emoji {
|
||||
width: 40px;
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
// TODO Copypaste from Status, should unify it somehow
|
||||
.Notification {
|
||||
&.-muted {
|
||||
|
|
|
@ -102,7 +102,18 @@
|
|||
<span v-if="notification.type === 'pleroma:emoji_reaction'">
|
||||
<small>
|
||||
<i18n path="notifications.reacted_with">
|
||||
<span class="emoji-reaction-emoji">{{ notification.emoji }}</span>
|
||||
<img
|
||||
v-if="notification.emoji_url !== null"
|
||||
class="notification-reaction-emoji"
|
||||
:src="notification.emoji_url"
|
||||
:name="notification.emoji"
|
||||
>
|
||||
<span
|
||||
v-else
|
||||
class="emoji-reaction-emoji"
|
||||
>
|
||||
{{ notification.emoji }}
|
||||
</span>
|
||||
</i18n>
|
||||
</small>
|
||||
</span>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Checkbox from '../checkbox/checkbox.vue'
|
||||
import Popover from '../popover/popover.vue'
|
||||
import EmojiPicker from '../emoji_picker/emoji_picker.vue'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faSmileBeam } from '@fortawesome/free-regular-svg-icons'
|
||||
|
||||
|
@ -9,26 +9,23 @@ const ReactButton = {
|
|||
props: ['status'],
|
||||
data () {
|
||||
return {
|
||||
filterWord: '',
|
||||
keepReactOpen: false
|
||||
filterWord: ''
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Popover,
|
||||
Checkbox
|
||||
EmojiPicker
|
||||
},
|
||||
methods: {
|
||||
addReaction (event, emoji, close, keepReactOpen) {
|
||||
addReaction (event, close) {
|
||||
const emoji = event.insertion
|
||||
const existingReaction = this.status.emoji_reactions.find(r => r.name === emoji)
|
||||
if (existingReaction && existingReaction.me) {
|
||||
this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
|
||||
} else {
|
||||
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
|
||||
}
|
||||
this.keepReactOpen = keepReactOpen
|
||||
if (!keepReactOpen) {
|
||||
close()
|
||||
}
|
||||
if (!event.keepOpen) { close() }
|
||||
},
|
||||
focusInput () {
|
||||
this.$nextTick(() => {
|
||||
|
@ -38,47 +35,6 @@ const ReactButton = {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
commonEmojis () {
|
||||
return [
|
||||
{ displayText: 'lying', replacement: '🤥' },
|
||||
{ displayText: 'thinking', replacement: '🤔' },
|
||||
{ displayText: 'zany', replacement: '🤪' },
|
||||
{ displayText: 'cartwheeling', replacement: '🤸♂️' },
|
||||
{ displayText: 'pills', replacement: '💊' },
|
||||
{ displayText: 'writing', replacement: '✍️' },
|
||||
{ displayText: 'pencil', replacement: '✏️' },
|
||||
{ displayText: 'chart_up', replacement: '📈' },
|
||||
{ displayText: 'chart_down', replacement: '📉' },
|
||||
{ displayText: 'question', replacement: '❔' },
|
||||
{ displayText: 'x', replacement: '❌' },
|
||||
{ displayText: 'orangutan', replacement: '🦧' },
|
||||
{ displayText: 'owl', replacement: '🦉' },
|
||||
{ displayText: 'bottle', replacement: '🍼' },
|
||||
{ displayText: 'crayon', replacement: '🖍️' },
|
||||
{ displayText: 'blackula', replacement: '🧛🏿' },
|
||||
{ displayText: 'wrench', replacement: '🔧' },
|
||||
{ displayText: 'axe', replacement: '🪓' }
|
||||
]
|
||||
},
|
||||
emojis () {
|
||||
if (this.filterWord !== '') {
|
||||
const filterWordLowercase = this.filterWord.toLowerCase()
|
||||
let orderedEmojiList = []
|
||||
for (const emoji of this.$store.state.instance.emoji) {
|
||||
if (emoji.replacement === this.filterWord) return [emoji]
|
||||
|
||||
const indexOfFilterWord = emoji.displayText.toLowerCase().indexOf(filterWordLowercase)
|
||||
if (indexOfFilterWord > -1) {
|
||||
if (!Array.isArray(orderedEmojiList[indexOfFilterWord])) {
|
||||
orderedEmojiList[indexOfFilterWord] = []
|
||||
}
|
||||
orderedEmojiList[indexOfFilterWord].push(emoji)
|
||||
}
|
||||
}
|
||||
return orderedEmojiList.flat()
|
||||
}
|
||||
return this.$store.state.instance.emoji || []
|
||||
},
|
||||
mergedConfig () {
|
||||
return this.$store.getters.mergedConfig
|
||||
}
|
||||
|
|
|
@ -9,40 +9,10 @@
|
|||
@show="focusInput"
|
||||
>
|
||||
<template v-slot:content="{close}">
|
||||
<div class="reaction-picker-filter">
|
||||
<input
|
||||
v-model="filterWord"
|
||||
size="1"
|
||||
:placeholder="$t('emoji.search_emoji')"
|
||||
>
|
||||
</div>
|
||||
<div class="keep-open">
|
||||
<Checkbox v-model="keepReactOpen">
|
||||
{{ $t('emoji.keep_open') }}
|
||||
</Checkbox>
|
||||
</div>
|
||||
<div class="reaction-picker">
|
||||
<span
|
||||
v-for="emoji in commonEmojis"
|
||||
:key="emoji.replacement"
|
||||
class="emoji-button"
|
||||
:title="emoji.displayText"
|
||||
@click="addReaction($event, emoji.replacement, close, keepReactOpen)"
|
||||
>
|
||||
{{ emoji.replacement }}
|
||||
</span>
|
||||
<div class="reaction-picker-divider" />
|
||||
<span
|
||||
v-for="(emoji, key) in emojis"
|
||||
:key="key"
|
||||
class="emoji-button"
|
||||
:title="emoji.displayText"
|
||||
@click="addReaction($event, emoji.replacement, close, keepReactOpen)"
|
||||
>
|
||||
{{ emoji.replacement }}
|
||||
</span>
|
||||
<div class="reaction-bottom-fader" />
|
||||
</div>
|
||||
<EmojiPicker
|
||||
:enableStickerPicker="false"
|
||||
@emoji="addReaction($event, close)"
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:trigger>
|
||||
<button
|
||||
|
@ -63,6 +33,10 @@
|
|||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.custom-reaction {
|
||||
width: 30px !important;
|
||||
}
|
||||
|
||||
.ReactButton {
|
||||
.reaction-picker-filter {
|
||||
padding: 0.5em;
|
||||
|
@ -129,15 +103,6 @@
|
|||
color: var(--text, $fallback--text);
|
||||
}
|
||||
}
|
||||
.keep-open,
|
||||
.too-many-emoji {
|
||||
padding: 7px;
|
||||
line-height: normal;
|
||||
}
|
||||
.keep-open-label {
|
||||
padding: 0 7px;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -392,6 +392,7 @@ export const parseNotification = (data) => {
|
|||
: parseUser(data.target)
|
||||
output.from_profile = parseUser(data.account)
|
||||
output.emoji = data.emoji
|
||||
output.emoji_url = data.emoji_url
|
||||
} else {
|
||||
const parsedNotice = parseStatus(data.notice)
|
||||
output.type = data.ntype
|
||||
|
|
Loading…
Reference in a new issue