Merge branch 'develop' into stable
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful

This commit is contained in:
FloatingGhost 2023-03-11 17:27:22 +00:00
commit 85abc62213
12 changed files with 162 additions and 16 deletions

View file

@ -51,6 +51,7 @@ const EmojiPicker = {
onEmoji (emoji) { onEmoji (emoji) {
const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement
this.$emit('emoji', { insertion: value, keepOpen: this.keepOpen }) this.$emit('emoji', { insertion: value, keepOpen: this.keepOpen })
this.$store.commit('emojiUsed', emoji)
}, },
onWheel (e) { onWheel (e) {
e.preventDefault() e.preventDefault()
@ -96,6 +97,7 @@ const EmojiPicker = {
) )
}, },
emojis () { emojis () {
const recentEmojis = this.$store.getters.recentEmojis
const standardEmojis = this.$store.state.instance.emoji || [] const standardEmojis = this.$store.state.instance.emoji || []
const customEmojis = this.sortedEmoji const customEmojis = this.sortedEmoji
const emojiPacks = [] const emojiPacks = []
@ -108,6 +110,15 @@ const EmojiPicker = {
}) })
}) })
return [ return [
{
id: 'recent',
text: this.$t('emoji.recent'),
first: {
imageUrl: '',
replacement: '🕒',
},
emojis: this.filterByKeyword(recentEmojis)
},
{ {
id: 'standard', id: 'standard',
text: this.$t('emoji.unicode'), text: this.$t('emoji.unicode'),

View file

@ -3,6 +3,11 @@ import UserListPopover from '../user_list_popover/user_list_popover.vue'
const EMOJI_REACTION_COUNT_CUTOFF = 12 const EMOJI_REACTION_COUNT_CUTOFF = 12
const findEmojiByReplacement = (state, replacement) => {
const allEmojis = state.instance.emoji.concat(state.instance.customEmoji)
return allEmojis.find(emoji => emoji.replacement === replacement)
}
const EmojiReactions = { const EmojiReactions = {
name: 'EmojiReactions', name: 'EmojiReactions',
components: { components: {
@ -54,6 +59,8 @@ const EmojiReactions = {
}, },
reactWith (emoji) { reactWith (emoji) {
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji }) this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
const emojiObject = findEmojiByReplacement(this.$store.state, emoji)
this.$store.commit('emojiUsed', emojiObject)
}, },
unreact (emoji) { unreact (emoji) {
this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji }) this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })

View file

@ -18,7 +18,6 @@
:src="reaction.url" :src="reaction.url"
:title="reaction.name" :title="reaction.name"
class="reaction-emoji" class="reaction-emoji"
width="2.55em"
height="2.55em" height="2.55em"
> >
{{ reaction.count }} {{ reaction.count }}
@ -50,6 +49,7 @@
display: flex; display: flex;
margin-top: 0.25em; margin-top: 0.25em;
flex-wrap: wrap; flex-wrap: wrap;
container-type: inline-size;
} }
.unicode-emoji { .unicode-emoji {
@ -65,7 +65,8 @@
justify-content: center; justify-content: center;
box-sizing: border-box; box-sizing: border-box;
.reaction-emoji { .reaction-emoji {
width: 2.55em !important; width: auto;
max-width: 96cqw;
height: 2.55em !important; height: 2.55em !important;
margin-right: 0.25em; margin-right: 0.25em;
} }

View file

@ -54,6 +54,14 @@ const pxStringToNumber = (str) => {
return Number(str.substring(0, str.length - 2)) return Number(str.substring(0, str.length - 2))
} }
const deleteDraft = (draftKey) => {
const draftData = JSON.parse(localStorage.getItem('drafts') || '{}');
delete draftData[draftKey];
localStorage.setItem('drafts', JSON.stringify(draftData));
}
const PostStatusForm = { const PostStatusForm = {
props: [ props: [
'statusId', 'statusId',
@ -161,6 +169,34 @@ const PostStatusForm = {
} }
} }
let draftKey = 'status';
if (this.replyTo) {
draftKey = 'reply:' + this.replyTo;
} else if (this.quoteId) {
draftKey = 'quote:' + this.quoteId;
}
const draft = JSON.parse(localStorage.getItem('drafts') || '{}')[draftKey];
if (draft) {
statusParams = {
spoilerText: draft.data.spoilerText,
status: draft.data.status,
sensitiveIfSubject,
nsfw: draft.data.nsfw,
files: draft.data.files,
poll: draft.data.poll,
mediaDescriptions: draft.data.mediaDescriptions,
visibility: draft.data.visibility,
language: draft.data.language,
contentType: draft.data.contentType
}
if (draft.data.poll) {
this.togglePollForm();
}
}
return { return {
dropFiles: [], dropFiles: [],
uploadingFiles: false, uploadingFiles: false,
@ -280,6 +316,7 @@ const PostStatusForm = {
statusChanged () { statusChanged () {
this.autoPreview() this.autoPreview()
this.updateIdempotencyKey() this.updateIdempotencyKey()
this.saveDraft()
}, },
clearStatus () { clearStatus () {
const newStatus = this.newStatus const newStatus = this.newStatus
@ -401,8 +438,38 @@ const PostStatusForm = {
}).finally(() => { }).finally(() => {
this.previewLoading = false this.previewLoading = false
}) })
let draftKey = 'status';
if (this.replyTo) {
draftKey = 'reply:' + this.replyTo;
} else if (this.quoteId) {
draftKey = 'quote:' + this.quoteId;
}
deleteDraft(draftKey)
}, },
debouncePreviewStatus: debounce(function () { this.previewStatus() }, 500), debouncePreviewStatus: debounce(function () { this.previewStatus() }, 500),
saveDraft() {
const draftData = JSON.parse(localStorage.getItem('drafts') || '{}');
let draftKey = 'status';
if (this.replyTo) {
draftKey = 'reply:' + this.replyTo;
} else if (this.quoteId) {
draftKey = 'quote:' + this.quoteId;
}
if (this.newStatus.status || this.newStatus.spoilerText || this.newStatus.files.length > 0 || this.newStatus.poll.length > 0) {
draftData[draftKey] = {
updatedAt: new Date(),
data: this.newStatus,
};
localStorage.setItem('drafts', JSON.stringify(draftData));
} else {
deleteDraft(draftKey);
}
},
autoPreview () { autoPreview () {
if (!this.preview) return if (!this.preview) return
this.previewLoading = true this.previewLoading = true

View file

@ -50,7 +50,6 @@
.emoji { .emoji {
display: inline-block; display: inline-block;
width: var(--emoji-size, 32px);
height: var(--emoji-size, 32px); height: var(--emoji-size, 32px);
} }

View file

@ -22,21 +22,18 @@
._mfm_x2_ { ._mfm_x2_ {
.emoji { .emoji {
width: 100px;
height: 100px; height: 100px;
} }
} }
._mfm_x3_ { ._mfm_x3_ {
.emoji { .emoji {
width: 150px;
height: 150px; height: 150px;
} }
} }
._mfm_x4_ { ._mfm_x4_ {
.emoji { .emoji {
width: 200px;
height: 200px; height: 200px;
} }
} }

View file

@ -71,7 +71,7 @@
img, video { img, video {
&.emoji { &.emoji {
width: 50px; max-width: 100%;
height: 50px; height: 50px;
} }
} }
@ -89,7 +89,6 @@
animation: none !important; animation: none !important;
} }
.emoji { .emoji {
width: 32px !important;
height: 32px !important; height: 32px !important;
} }
} }

View file

@ -86,7 +86,8 @@
"load_all_hint": "Loaded first {saneAmount} emoji, loading all emoji may cause performance issues.", "load_all_hint": "Loaded first {saneAmount} emoji, loading all emoji may cause performance issues.",
"search_emoji": "Search for an emoji", "search_emoji": "Search for an emoji",
"stickers": "Stickers", "stickers": "Stickers",
"unicode": "Unicode emoji" "unicode": "Unicode emoji",
"recent": "Recently used"
}, },
"errors": { "errors": {
"storage_unavailable": "Pleroma could not access browser storage. Your login or your local settings won't be saved and you might encounter unexpected issues. Try enabling cookies." "storage_unavailable": "Pleroma could not access browser storage. Your login or your local settings won't be saved and you might encounter unexpected issues. Try enabling cookies."

View file

@ -19,7 +19,8 @@ const saveImmedeatelyActions = [
'setOption', 'setOption',
'setClientData', 'setClientData',
'setToken', 'setToken',
'clearToken' 'clearToken',
'emojiUsed',
] ]
const defaultStorage = (() => { const defaultStorage = (() => {

View file

@ -22,6 +22,7 @@ import announcementsModule from './modules/announcements.js'
import editStatusModule from './modules/editStatus.js' import editStatusModule from './modules/editStatus.js'
import statusHistoryModule from './modules/statusHistory.js' import statusHistoryModule from './modules/statusHistory.js'
import tagModule from './modules/tags.js' import tagModule from './modules/tags.js'
import recentEmojisModule from './modules/recentEmojis.js'
import { createI18n } from 'vue-i18n' import { createI18n } from 'vue-i18n'
@ -47,7 +48,8 @@ const persistedStateOptions = {
paths: [ paths: [
'config', 'config',
'users.lastLoginName', 'users.lastLoginName',
'oauth' 'oauth',
'recentEmojis.emojis',
] ]
}; };
@ -98,7 +100,8 @@ const persistedStateOptions = {
announcements: announcementsModule, announcements: announcementsModule,
editStatus: editStatusModule, editStatus: editStatusModule,
statusHistory: statusHistoryModule, statusHistory: statusHistoryModule,
tags: tagModule tags: tagModule,
recentEmojis: recentEmojisModule,
}, },
plugins, plugins,
strict: false // Socket modifies itself, let's ignore this for now. strict: false // Socket modifies itself, let's ignore this for now.

View file

@ -5,15 +5,25 @@ import { map } from 'lodash'
const retryTimeout = (multiplier) => 1000 * multiplier const retryTimeout = (multiplier) => 1000 * multiplier
const isVisible = (store, message, visibility) => { const isVisible = (store, message, visibility) => {
if (visibility === 'all') { if (visibility == 'all') {
return true return true
} else if (visibility === 'following') { }
return store.getters.relationship(message.in_reply_to_user_id).following
} else if (visibility === 'self') { if (visibility == 'following') {
if (message.in_reply_to_user_id === null) {
return true
} else {
return store.getters.relationship(message.in_reply_to_user_id).following
}
}
if (visibility == 'self') {
return message.in_reply_to_user_id === store.rootState.users.currentUser.id return message.in_reply_to_user_id === store.rootState.users.currentUser.id
} }
return false return false
} }
const api = { const api = {
state: { state: {
retryMultiplier: 1, retryMultiplier: 1,

View file

@ -0,0 +1,50 @@
// each row is 7 emojis, 6 rows chosen arbitrarily. i don't think more than
// that are going to be useful.
const RECENT_MAX = 7 * 6
const defaultState = {
emojis: [],
}
const recentEmojis = {
state: defaultState,
mutations: {
emojiUsed ({ emojis }, emoji) {
if (emoji.displayText === undefined || emoji.displayText === null) {
console.error('emojiUsed was called with a bad emoji object: ', emoji)
return
} else if (emoji.displayText.includes('@')) {
console.error('emojiUsed was called with a remote emoji: ', emoji)
return
}
const i = emojis.indexOf(emoji.displayText)
if (i === -1) {
// not in `emojis` yet, insert and truncate if necessary
const newLength = emojis.unshift(emoji.displayText)
if (newLength > RECENT_MAX) {
emojis.pop()
}
} else if (i !== 0) {
// emoji is already in `emojis` but needs to be bumped to the top
emojis.splice(i, 1)
emojis.unshift(emoji.displayText)
}
},
},
getters: {
recentEmojis: (state, getters, rootState) => state.emojis.reduce((objects, displayText) => {
const allEmojis = rootState.instance.emoji.concat(rootState.instance.customEmoji)
let emojiObject = allEmojis.find(emoji => emoji.displayText === displayText)
if (emojiObject !== undefined) {
objects.push(emojiObject)
}
return objects
}, []),
},
}
export default recentEmojis