Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85830084
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
14 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/components/chat_message/chat_message.js b/src/components/chat_message/chat_message.js
index 8444899e26..f88a60010a 100644
--- a/src/components/chat_message/chat_message.js
+++ b/src/components/chat_message/chat_message.js
@@ -1,163 +1,164 @@
import { find } from 'lodash'
import { mapState as mapPiniaState } from 'pinia'
import { mapState } from 'vuex'
import Attachment from 'src/components/attachment/attachment.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'
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 UserAvatar from 'src/components/user_avatar/user_avatar.vue'
import UserPopover from 'src/components/user_popover/user_popover.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faCircleNotch,
faEllipsisH,
faTimes,
} from '@fortawesome/free-solid-svg-icons'
library.add(faTimes, faEllipsisH, faCircleNotch)
const ChatMessage = {
name: 'ChatMessage',
props: [
'edited',
'noHeading',
'previousItem',
'chatItem',
'previousItem',
'hoveredMessageChain',
],
emits: ['hover', 'replyRequested'],
components: {
Popover,
Attachment,
StatusContent,
StatusBody,
StatusActionButtons,
UserAvatar,
Gallery,
LinkPreview,
ChatMessageDate,
UserPopover,
},
computed: {
// Returns HH:MM (hours and minutes) in local time.
createdAt() {
const time = this.chatItem.data.created_at
return time.toLocaleTimeString('en', {
hour: '2-digit',
minute: '2-digit',
hour12: false,
})
},
isStatus() {
// ChatMessage only has account_id while Status has full user data
return !!this.message.user
},
author() {
const accountId = this.message.account_id || this.message.user.id
return this.$store.getters.findUser(accountId)
},
isCurrentUser() {
return this.author.id === this.currentUser.id
},
message() {
return this.isMessage ? this.chatItem.data : null
},
isMessage() {
return this.chatItem.type === 'message'
},
isCustomReply() {
if (!this.previousItem) return false
+ if (!this.chatItem.data.in_reply_to_status_id) return false
console.log('==')
- console.log('PREV', toValue(this.previousItem.data.raw_html))
- console.log('CURR', toValue(this.chatItem.data.raw_html))
+ console.log('PREV', toValue(this.previousItem.data.text))
+ console.log('CURR', toValue(this.chatItem.data.text))
return (
this.previousItem.data.id !== this.chatItem.data.in_reply_to_status_id
)
},
customReplyTo() {
- return find(this.$store.state.statuses.allStatuses, {
- id: this.chatItem.data.in_reply_to_status_id,
- })
+ return this.$store.state.statuses.allStatusesObject[
+ this.chatItem.data.in_reply_to_status_id
+ ]
},
messageForStatusContent() {
return {
summary: '',
emojis: this.message.emojis,
raw_html: this.message.content || this.message.raw_html || '',
text: this.message.content || '',
attachments: this.message.attachments,
}
},
hasAttachment() {
return this.message.attachments.length > 0
},
...mapPiniaState(useInterfaceStore, {
betterShadow: (store) => store.browserSupport.cssFilter,
}),
...mapState({
currentUser: (state) => state.users.currentUser,
restrictedNicknames: (state) => useInstanceStore().restrictedNicknames,
}),
popoverMarginStyle() {
if (this.isCurrentUser) {
return {}
} else {
return { left: 50 }
}
},
...mapPiniaState(useMergedConfigStore, ['mergedConfig', 'findUser']),
},
data() {
return {
hovered: false,
menuOpened: false,
}
},
methods: {
onHover(bool) {
this.$emit('hover', {
isHovered: bool,
messageChainId: this.chatItem.messageChainId,
})
},
visibilityIcon(visibility) {
switch (visibility) {
case 'private':
return 'lock'
case 'unlisted':
return 'lock-open'
case 'direct':
return 'envelope'
case 'local':
return 'igloo'
default:
return 'globe'
}
},
async deleteMessage() {
const confirmed = window.confirm(this.$t('chats.delete_confirm'))
if (confirmed) {
await this.$emit('delete', {
messageId: this.chatItem.data.id,
chatId: this.chatItem.data.chat_id,
})
}
this.hovered = false
this.menuOpened = false
},
},
}
export default ChatMessage
diff --git a/src/components/chat_message/chat_message.vue b/src/components/chat_message/chat_message.vue
index b1fa85fe77..91ad9a4ebe 100644
--- a/src/components/chat_message/chat_message.vue
+++ b/src/components/chat_message/chat_message.vue
@@ -1,150 +1,152 @@
<template>
<div
v-if="isMessage"
class="chat-message-wrapper"
:class="{ 'hovered-message-chain': hoveredMessageChain }"
@mouseover="onHover(true)"
@mouseleave="onHover(false)"
>
<div
class="chat-message"
:class="[{ '-outgoing': isCurrentUser, '-incoming': !isCurrentUser, '-pending': message.pending }]"
>
<div
v-if="!isCurrentUser"
class="avatar-wrapper"
>
<UserPopover
v-if="chatItem.isHead"
:user-id="author.id"
>
<UserAvatar
:compact="true"
:user="author"
/>
</UserPopover>
</div>
<div class="chat-message-inner">
<small
v-if="isStatus && isCustomReply"
class="reply-to-header faint"
>
<strong class="reply-label">
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="reply"
flip="horizontal"
/>
{{ $t('status.reply_to') }}
</strong>
+ <!-- v-if is there because status might not be loaded yet -->
<StatusBody
+ v-if="customReplyTo"
class="reply-body"
:status="customReplyTo"
collapse
single-line
/>
</small>
<div
class="status-body"
:style="{ 'min-width': message.attachment ? '80%' : '' }"
>
<div
class="media status"
:class="{ 'without-attachment': !hasAttachment, 'pending': chatItem.data.pending, 'error': chatItem.data.error }"
style="position: relative;"
@mouseenter="hovered = true"
@mouseleave="hovered = false"
>
<StatusActionButtons
v-if="isStatus"
class="chat-message-toolbar"
:class="{ '-visible': hovered || menuOpened }"
:status="message"
:pinned="new Set(['reply', 'emoji'])"
fixed-pinned
use-default-buttons
hide-labels
@toggle-replying="$emit('replyRequested', message)"
/>
<div
class="chat-message-toolbar"
:class="{ '-visible': hovered || menuOpened }"
v-else
>
<Popover
trigger="click"
:trigger-attrs="{ 'class': 'button-default menu-icon simple-button', title: $t('chats.more') }"
placement="top"
:margin="popoverMarginStyle"
@show="menuOpened = true"
@close="menuOpened = false"
>
<template #content>
<div class="dropdown-menu">
<div class="menu-item dropdown-item -icon">
<button
class="main-button"
@click="deleteMessage"
>
<FAIcon icon="times" /> {{ $t("chats.delete") }}
</button>
</div>
</div>
</template>
<template #trigger>
<FAIcon icon="ellipsis-h" />
</template>
</Popover>
</div>
<StatusContent
class="message-content"
:class="{ faint: message.pending }"
:status="messageForStatusContent"
:full-content="true"
>
<template #footer>
<span
class="created-at"
>
<span
v-if="message.visibility"
class="visibility-icon"
:title="visibilityLocalized"
>
<FAIcon
class="fa-scale-110"
:icon="visibilityIcon(message.visibility)"
fixed-width
/>
</span>
<span
v-if="message.pending"
class="loading-spinner"
>
<FAIcon
class="fa-old-padding"
icon="circle-notch"
spin
/>
</span>
{{ createdAt }}
</span>
</template>
</StatusContent>
</div>
</div>
</div>
</div>
</div>
<div
v-else
class="chat-message-date-separator"
>
<ChatMessageDate :date="chatItem.date" :show-time="chatItem.isTime" />
</div>
</template>
<script src="./chat_message.js"></script>
<style src="./chat_message.scss" lang="scss" />
diff --git a/src/components/status_body/status_body.scss b/src/components/status_body/status_body.scss
index 9954663e78..f248e8099e 100644
--- a/src/components/status_body/status_body.scss
+++ b/src/components/status_body/status_body.scss
@@ -1,196 +1,196 @@
.StatusBody {
display: flex;
flex-direction: column;
.emoji {
--_still_image-label-scale: 0.5;
}
.attachments {
margin-top: 0.5em;
}
& .text,
& .summary {
white-space: pre-wrap;
overflow-wrap: break-word;
text-wrap: pretty;
line-height: var(--post-line-height);
}
.summary {
display: block;
font-style: italic;
padding-bottom: 0.5em;
}
.text {
&.-single-line {
- white-space: nowrap;
+ white-space-collapse: collapse;
text-overflow: ellipsis;
overflow: hidden;
height: 1.4em;
}
}
.summary-wrapper {
margin-bottom: 0.5em;
border-style: solid;
border-width: 0 0 1px;
border-color: var(--border);
flex-grow: 0;
&.-tall {
position: relative;
.summary {
max-height: 2em;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
.text-wrapper {
position: relative;
text-overflow: ellipsis;
overflow-wrap: break-word;
overflow: hidden;
display: flex;
flex-flow: column nowrap;
&.-tall-status {
z-index: 1;
&:not(.-hidden) {
height: 16em;
}
.media-body {
min-height: 0;
mask:
linear-gradient(to top, white, transparent) bottom/100% 8em no-repeat,
linear-gradient(to top, white, white);
/* Autoprefixed seem to ignore this one, and also syntax is different */
/* stylelint-disable mask-composite */
/* stylelint-disable declaration-property-value-no-unknown */
/* stylelint-disable scss/declaration-property-value-no-unknown */
/* TODO check if this is still needed */
mask-composite: xor;
/* stylelint-enable scss/declaration-property-value-no-unknown */
/* stylelint-enable declaration-property-value-no-unknown */
/* stylelint-enable mask-composite */
mask-composite: exclude;
}
}
&.-expanded {
overflow: visible;
}
}
& .tall-status-hider,
& .tall-subject-hider,
& .status-unhider,
& .cw-status-hider {
display: inline-block;
overflow-wrap: break-word;
text-wrap: pretty;
width: 100%;
text-align: center;
margin: 0.1em 0;
}
.status-unhider {
margin-top: auto;
position: sticky;
bottom: 0;
padding-bottom: 1em;
}
.tall-subject-hider {
// position: absolute;
padding-bottom: 0.5em;
&:not(.cw-status-hider) {
position: absolute;
margin-top: 10em;
height: 5em;
line-height: 8em;
z-index: 2;
}
}
& .status-unhider,
& .cw-status-hider {
overflow-wrap: break-word;
text-wrap: pretty;
svg {
color: inherit;
}
}
.toggle-button {
padding: 0.5em;
}
&.-compact {
align-items: start;
flex-direction: row;
& .body,
& .attachments {
max-height: 3.25em;
}
.body {
overflow: hidden;
white-space: normal;
min-width: 5em;
flex: 5 1 auto;
mask-size: auto 3.5em, auto auto;
mask-position: 0 0, 0 0;
mask-repeat: repeat-x, repeat;
mask-image: linear-gradient(to bottom, white 2em, transparent 3em);
/* Autoprefixed seem to ignore this one, and also syntax is different */
/* stylelint-disable mask-composite */
/* stylelint-disable declaration-property-value-no-unknown */
/* stylelint-disable scss/declaration-property-value-no-unknown */
/* TODO check if this is still needed */
mask-composite: xor;
/* stylelint-enable scss/declaration-property-value-no-unknown */
/* stylelint-enable declaration-property-value-no-unknown */
/* stylelint-enable mask-composite */
mask-composite: exclude;
}
.attachments {
margin-top: 0;
flex: 1 1 0;
min-width: 5em;
height: 100%;
margin-left: 0.5em;
}
.summary-wrapper {
.summary::after {
content: ": ";
}
line-height: inherit;
margin: 0;
border: none;
}
.text-wrapper {
display: inline-block;
width: 100%;
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Nov 1, 1:46 AM (19 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1802180
Default Alt Text
(14 KB)
Attached To
Mode
rPUFE pleroma-fe-upstream
Attached
Detach File
Event Timeline