diff --git a/src/components/chat_message/chat_message.js b/src/components/chat_message/chat_message.js index 1595e4dde..a71014078 100644 --- a/src/components/chat_message/chat_message.js +++ b/src/components/chat_message/chat_message.js @@ -2,6 +2,7 @@ import { mapState as mapPiniaState } from 'pinia' import { mapState } from 'vuex' import Attachment from 'src/components/attachment/attachment.vue' +import MentionLink from 'src/components/mention_link/mention_link.vue' import ChatMessageDate from 'src/components/chat_message_date/chat_message_date.vue' import Gallery from 'src/components/gallery/gallery.vue' import LinkPreview from 'src/components/link-preview/link-preview.vue' @@ -9,6 +10,7 @@ import Popover from 'src/components/popover/popover.vue' import StatusActionButtons from 'src/components/status_action_buttons/status_action_buttons.vue' import StatusBody from 'src/components/status_body/status_body.vue' import StatusContent from 'src/components/status_content/status_content.vue' +import StatusPopover from 'src/components/status_popover/status_popover.vue' import UserAvatar from 'src/components/user_avatar/user_avatar.vue' import UserPopover from 'src/components/user_popover/user_popover.vue' @@ -21,9 +23,10 @@ import { faCircleNotch, faEllipsisH, faTimes, + faReply, } from '@fortawesome/free-solid-svg-icons' -library.add(faTimes, faEllipsisH, faCircleNotch) +library.add(faTimes, faEllipsisH, faCircleNotch, faReply) const ChatMessage = { name: 'ChatMessage', @@ -34,6 +37,8 @@ const ChatMessage = { 'chatItem', 'previousItem', 'hoveredMessageChain', + 'focused', + 'repliedTo', ], emits: ['hover', 'replyRequested'], components: { @@ -47,6 +52,8 @@ const ChatMessage = { LinkPreview, ChatMessageDate, UserPopover, + StatusPopover, + MentionLink, }, computed: { // Returns HH:MM (hours and minutes) in local time. @@ -88,6 +95,25 @@ const ChatMessage = { this.chatItem.data.in_reply_to_status_id ] }, + replyToName() { + if (this.message.in_reply_to_screen_name) { + return this.message.in_reply_to_screen_name + } else { + const user = this.$store.getters.findUser( + this.status.in_reply_to_user_id, + ) + return user && user.screen_name_ui + } + }, + replyProfileLink() { + if (this.isCustomReply) { + const user = this.$store.getters.findUser( + this.message.in_reply_to_user_id, + ) + // FIXME Why user not found sometimes??? + return user ? user.statusnet_profile_url : 'NOT_FOUND' + } + }, messageForStatusContent() { return { summary: '', @@ -100,6 +126,14 @@ const ChatMessage = { hasAttachment() { return this.message.attachments.length > 0 }, + classnames() { + return { + '-outgoing': this.isCurrentUser, + '-incoming': !this.isCurrentUser, + '-pending': this.message.pending, + '-focused': this.focused, + } + }, ...mapPiniaState(useInterfaceStore, { betterShadow: (store) => store.browserSupport.cssFilter, }), diff --git a/src/components/chat_message/chat_message.scss b/src/components/chat_message/chat_message.scss index 34382c42d..0d5db41b2 100644 --- a/src/components/chat_message/chat_message.scss +++ b/src/components/chat_message/chat_message.scss @@ -17,7 +17,7 @@ position: absolute; top: -0.8em; right: 0.4rem; - z-index: 10; + z-index: 1; .quick-action-buttons { justify-items: end; @@ -39,23 +39,16 @@ } .reply-to-header { - white-space: nowrap; - width: 100%; display: flex; - align-items: baseline; - gap: 0.5em; + gap: 0.5rem; + align-items: center; + padding: 0.125em 0; + width: 100%; + } - .reply-label { - display: inline-block; - line-height: 1; - } - - .reply-body { - line-height: 1; - display: inline-block; - overflow-x: hidden; - text-overflow: ellipsis; - } + .avatar-spacer { + flex: 0 0 2.2rem; + width: 2.2rem; } .popover { @@ -73,8 +66,7 @@ } .avatar-wrapper { - margin-right: 0.72em; - width: 32px; + margin-right: 0.5em; } .link-preview, @@ -124,27 +116,70 @@ } } + .message-bubble-wrapper { + display: flex; + } + .chat-message-inner { display: flex; flex-direction: column; align-items: flex-start; - max-width: 80%; - min-width: 10em; - width: 100%; } - .-outgoing { + .reply-indicator { display: flex; - flex-flow: row wrap; - place-content: end flex-end; + place-items: center; + place-content: center; + padding: 0.25em; + margin: var(--roundness) 0; + background: var(--border); + border-radius: var(--roundness); + border: 1px solid var(--border); + } - .chat-message-inner { - align-items: flex-end; + .end-spacer { + flex: 1 1 0; + min-width: calc(2.2em + 0.5em + 2em); + } + + &.-incoming { + .reply-indicator { + border-bottom-left-radius: 0; + border-top-left-radius: 0; + } + } + + .reply-to-popover { + white-space: nowrap; + } + + .reply-label { + white-space: nowrap; + } + + &.-outgoing { + &, + .message-bubble-wrapper, + .chat-message{ + flex-direction: row-reverse; } .reply-to-header { justify-content: end; } + + .reply-indicator { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + + .icon { + transform: scaleX(-1); + } + } + + .chat-message-inner { + align-items: flex-end; + } } .chat-message-inner.with-media { diff --git a/src/components/chat_message/chat_message.style.js b/src/components/chat_message/chat_message.style.js index f7632bc6f..67f0ae6c1 100644 --- a/src/components/chat_message/chat_message.style.js +++ b/src/components/chat_message/chat_message.style.js @@ -4,6 +4,9 @@ export default { variants: { outgoing: '.outgoing', }, + states: { + focused: '.-focused', + }, validInnerComponents: ['Text', 'Icon', 'Border', 'PollGraph'], defaultRules: [ { @@ -18,5 +21,11 @@ export default { background: '--bg, 5', }, }, + { + state: ['focused'], + directives: { + background: '--inheritedBackground, 10', + }, + }, ], } diff --git a/src/components/chat_message/chat_message.vue b/src/components/chat_message/chat_message.vue index 91ad9a4eb..234d20cb2 100644 --- a/src/components/chat_message/chat_message.vue +++ b/src/components/chat_message/chat_message.vue @@ -2,13 +2,64 @@
+ + + +
+
- - - - {{ $t('status.reply_to') }} - - - - -
+
- -
- +
- - - -
- - + +
+
+ +
+
diff --git a/src/components/chat_message_list/chat_message_list.js b/src/components/chat_message_list/chat_message_list.js index 4babea5a7..a51e6a0e4 100644 --- a/src/components/chat_message_list/chat_message_list.js +++ b/src/components/chat_message_list/chat_message_list.js @@ -14,6 +14,8 @@ const ChatMessageList = { default: [], }, headerDate: Boolean, + focusedId: String, + repliedId: String, }, data() { return { diff --git a/src/components/chat_message_list/chat_message_list.vue b/src/components/chat_message_list/chat_message_list.vue index cd1688a8c..5cdbf6871 100644 --- a/src/components/chat_message_list/chat_message_list.vue +++ b/src/components/chat_message_list/chat_message_list.vue @@ -6,6 +6,8 @@ :chat-item="chatItem" :previous-item="getPreviousItem(index)" :hovered-message-chain="chatItem.messageChainId === hoveredMessageChainId" + :focused="chatItem.id === focusedId" + :repliedTo="chatItem.id === repliedId" @hover="onMessageHover" @delete="onMessageDelete" @reply-requested="onReplyRequested" diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 079897f4a..19d63fbbe 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -202,6 +202,8 @@ >
diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx index 432250548..eb73e263c 100644 --- a/src/components/rich_content/rich_content.jsx +++ b/src/components/rich_content/rich_content.jsx @@ -479,7 +479,8 @@ export default { > {this.collapse ? pass2.map((x) => { - if (!Array.isArray(x)) return x.replace(/\n/g, ' ') + if (typeof x === 'string') return x.replace(/\n/g, ' ') + if (!Array.isArray(x)) return x return x.map((y) => (y.type === 'br' ? ' ' : y)) }) : pass2}