mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-23 11:31:57 +03:00
Chunter: Copy link to message (#2078)
Signed-off-by: Denis Bunakalya <denis.bunakalya@xored.com>
This commit is contained in:
parent
e0853ecf99
commit
9d772b786f
@ -16,13 +16,16 @@ let currentLocation: string | undefined
|
|||||||
location.subscribe((loc) => {
|
location.subscribe((loc) => {
|
||||||
if (loc.fragment !== currentLocation && loc.fragment !== undefined && loc.fragment.trim().length > 0) {
|
if (loc.fragment !== currentLocation && loc.fragment !== undefined && loc.fragment.trim().length > 0) {
|
||||||
const props = decodeURIComponent(loc.fragment).split('|')
|
const props = decodeURIComponent(loc.fragment).split('|')
|
||||||
showPanel(
|
|
||||||
props[0] as AnyComponent,
|
if (props.length >= 3) {
|
||||||
props[1],
|
showPanel(
|
||||||
props[2],
|
props[0] as AnyComponent,
|
||||||
(props[3] ?? undefined) as PopupAlignment,
|
props[1],
|
||||||
(props[4] ?? undefined) as AnyComponent
|
props[2],
|
||||||
)
|
(props[3] ?? undefined) as PopupAlignment,
|
||||||
|
(props[4] ?? undefined) as AnyComponent
|
||||||
|
)
|
||||||
|
}
|
||||||
} else if (
|
} else if (
|
||||||
(loc.fragment === undefined || (loc.fragment !== undefined && loc.fragment.trim().length === 0)) &&
|
(loc.fragment === undefined || (loc.fragment !== undefined && loc.fragment.trim().length === 0)) &&
|
||||||
currentLocation !== undefined
|
currentLocation !== undefined
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
"ThreadMessage": "Thread message",
|
"ThreadMessage": "Thread message",
|
||||||
"ChunterBrowser": "Search",
|
"ChunterBrowser": "Search",
|
||||||
"Messages": "Messages",
|
"Messages": "Messages",
|
||||||
"NoResults": "No results"
|
"NoResults": "No results",
|
||||||
|
"CopyLink": "Copy link"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -64,6 +64,7 @@
|
|||||||
"ThreadMessage": "Сообщение в обсуждении",
|
"ThreadMessage": "Сообщение в обсуждении",
|
||||||
"ChunterBrowser": "Поиск",
|
"ChunterBrowser": "Поиск",
|
||||||
"Messages": "Сообщения",
|
"Messages": "Сообщения",
|
||||||
"NoResults": "Нет результатов"
|
"NoResults": "Нет результатов",
|
||||||
|
"CopyLink": "Копировать ссылку"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,6 +19,7 @@
|
|||||||
import core, { Doc, Ref, Space, Timestamp, WithLookup } from '@anticrm/core'
|
import core, { Doc, Ref, Space, Timestamp, WithLookup } from '@anticrm/core'
|
||||||
import { NotificationClientImpl } from '@anticrm/notification-resources'
|
import { NotificationClientImpl } from '@anticrm/notification-resources'
|
||||||
import { createQuery } from '@anticrm/presentation'
|
import { createQuery } from '@anticrm/presentation'
|
||||||
|
import { getCurrentLocation, navigate } from '@anticrm/ui'
|
||||||
import { afterUpdate, beforeUpdate } from 'svelte'
|
import { afterUpdate, beforeUpdate } from 'svelte'
|
||||||
import chunter from '../plugin'
|
import chunter from '../plugin'
|
||||||
import { getDay } from '../utils'
|
import { getDay } from '../utils'
|
||||||
@ -34,12 +35,27 @@
|
|||||||
|
|
||||||
let div: HTMLDivElement | undefined
|
let div: HTMLDivElement | undefined
|
||||||
let autoscroll: boolean = false
|
let autoscroll: boolean = false
|
||||||
|
let messageIdForScroll = ''
|
||||||
|
let isMessageHighlighted = false
|
||||||
|
|
||||||
beforeUpdate(() => {
|
beforeUpdate(() => {
|
||||||
autoscroll = div !== undefined && div.offsetHeight + div.scrollTop > div.scrollHeight - 20
|
autoscroll = div !== undefined && div.offsetHeight + div.scrollTop > div.scrollHeight - 20
|
||||||
})
|
})
|
||||||
|
|
||||||
afterUpdate(() => {
|
afterUpdate(() => {
|
||||||
|
if (messageIdForScroll && !isMessageHighlighted) {
|
||||||
|
const messageElement = document.getElementById(messageIdForScroll)
|
||||||
|
|
||||||
|
messageElement?.scrollIntoView()
|
||||||
|
isMessageHighlighted = true
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
messageIdForScroll = ''
|
||||||
|
isMessageHighlighted = false
|
||||||
|
}, 2000)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
if (div && (autoscroll || isScrollForced)) {
|
if (div && (autoscroll || isScrollForced)) {
|
||||||
div.scrollTo(0, div.scrollHeight)
|
div.scrollTo(0, div.scrollHeight)
|
||||||
isScrollForced = false
|
isScrollForced = false
|
||||||
@ -85,6 +101,15 @@
|
|||||||
messages = res
|
messages = res
|
||||||
newMessagesPos = newMessagesStart(messages)
|
newMessagesPos = newMessagesStart(messages)
|
||||||
notificationClient.updateLastView(space, chunter.class.ChunterSpace)
|
notificationClient.updateLastView(space, chunter.class.ChunterSpace)
|
||||||
|
|
||||||
|
const location = getCurrentLocation()
|
||||||
|
const messageId = location.fragment
|
||||||
|
|
||||||
|
if (messageId && location.path.length === 3) {
|
||||||
|
messageIdForScroll = messageId
|
||||||
|
location.fragment = undefined
|
||||||
|
navigate(location)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
lookup: {
|
lookup: {
|
||||||
@ -205,6 +230,7 @@
|
|||||||
<JumpToDateSelector selectedDate={message.createOn} on:jumpToDate={handleJumpToDate} />
|
<JumpToDateSelector selectedDate={message.createOn} on:jumpToDate={handleJumpToDate} />
|
||||||
{/if}
|
{/if}
|
||||||
<MessageComponent
|
<MessageComponent
|
||||||
|
isHighlighted={messageIdForScroll === message._id && isMessageHighlighted}
|
||||||
{message}
|
{message}
|
||||||
{employees}
|
{employees}
|
||||||
on:openThread
|
on:openThread
|
||||||
|
@ -22,7 +22,17 @@
|
|||||||
import { NotificationClientImpl } from '@anticrm/notification-resources'
|
import { NotificationClientImpl } from '@anticrm/notification-resources'
|
||||||
import { getResource } from '@anticrm/platform'
|
import { getResource } from '@anticrm/platform'
|
||||||
import { Avatar, getClient, MessageViewer } from '@anticrm/presentation'
|
import { Avatar, getClient, MessageViewer } from '@anticrm/presentation'
|
||||||
import ui, { ActionIcon, IconMoreH, Menu, showPopup, Label, Tooltip, Button } from '@anticrm/ui'
|
import ui, {
|
||||||
|
ActionIcon,
|
||||||
|
IconMoreH,
|
||||||
|
Menu,
|
||||||
|
showPopup,
|
||||||
|
Label,
|
||||||
|
Tooltip,
|
||||||
|
Button,
|
||||||
|
getCurrentLocation,
|
||||||
|
locationToUrl
|
||||||
|
} from '@anticrm/ui'
|
||||||
import { Action } from '@anticrm/view'
|
import { Action } from '@anticrm/view'
|
||||||
import { getActions, LinkPresenter } from '@anticrm/view-resources'
|
import { getActions, LinkPresenter } from '@anticrm/view-resources'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
@ -42,6 +52,7 @@
|
|||||||
export let thread: boolean = false
|
export let thread: boolean = false
|
||||||
export let isPinned: boolean = false
|
export let isPinned: boolean = false
|
||||||
export let isSaved: boolean = false
|
export let isSaved: boolean = false
|
||||||
|
export let isHighlighted = false
|
||||||
|
|
||||||
let refInput: AttachmentRefInput
|
let refInput: AttachmentRefInput
|
||||||
|
|
||||||
@ -95,6 +106,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const copyLinkAction = {
|
||||||
|
label: chunter.string.CopyLink,
|
||||||
|
action: async () => {
|
||||||
|
const location = getCurrentLocation()
|
||||||
|
|
||||||
|
location.fragment = message._id
|
||||||
|
location.path[2] = message.space
|
||||||
|
|
||||||
|
if (message.attachedToClass === chunter.class.Message) {
|
||||||
|
location.path.length = 4
|
||||||
|
location.path[3] = message.attachedTo
|
||||||
|
} else {
|
||||||
|
location.path.length = 3
|
||||||
|
}
|
||||||
|
await navigator.clipboard.writeText(`${window.location.origin}${locationToUrl(location)}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let menuShowed = false
|
let menuShowed = false
|
||||||
|
|
||||||
const showMenu = async (ev: Event): Promise<void> => {
|
const showMenu = async (ev: Event): Promise<void> => {
|
||||||
@ -115,6 +144,7 @@
|
|||||||
await impl(message, evt)
|
await impl(message, evt)
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
|
copyLinkAction,
|
||||||
...(getCurrentAccount()._id === message.createBy ? [editAction, deleteAction] : [])
|
...(getCurrentAccount()._id === message.createBy ? [editAction, deleteAction] : [])
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -176,7 +206,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container" class:highlighted={isHighlighted} id={message._id}>
|
||||||
<div class="avatar"><Avatar size={'medium'} avatar={employee?.avatar} /></div>
|
<div class="avatar"><Avatar size={'medium'} avatar={employee?.avatar} /></div>
|
||||||
<div class="message">
|
<div class="message">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
@ -253,11 +283,20 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@keyframes highlight {
|
||||||
|
50% {
|
||||||
|
background-color: var(--warning-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
.container {
|
.container {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0.5rem 2rem;
|
padding: 0.5rem 2rem;
|
||||||
|
|
||||||
|
&.highlighted {
|
||||||
|
animation: highlight 2000ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
min-width: 2.25rem;
|
min-width: 2.25rem;
|
||||||
}
|
}
|
||||||
|
@ -40,12 +40,27 @@
|
|||||||
let div: HTMLDivElement | undefined
|
let div: HTMLDivElement | undefined
|
||||||
let autoscroll: boolean = false
|
let autoscroll: boolean = false
|
||||||
let isScrollForced = false
|
let isScrollForced = false
|
||||||
|
let messageIdForScroll = ''
|
||||||
|
let isMessageHighlighted = false
|
||||||
|
|
||||||
beforeUpdate(() => {
|
beforeUpdate(() => {
|
||||||
autoscroll = div !== undefined && div.offsetHeight + div.scrollTop > div.scrollHeight - 20
|
autoscroll = div !== undefined && div.offsetHeight + div.scrollTop > div.scrollHeight - 20
|
||||||
})
|
})
|
||||||
|
|
||||||
afterUpdate(() => {
|
afterUpdate(() => {
|
||||||
|
if (messageIdForScroll && !isMessageHighlighted) {
|
||||||
|
const messageElement = document.getElementById(messageIdForScroll)
|
||||||
|
|
||||||
|
messageElement?.scrollIntoView()
|
||||||
|
isMessageHighlighted = true
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
messageIdForScroll = ''
|
||||||
|
isMessageHighlighted = false
|
||||||
|
}, 2000)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
if (div && (autoscroll || isScrollForced)) {
|
if (div && (autoscroll || isScrollForced)) {
|
||||||
div.scrollTo(0, div.scrollHeight)
|
div.scrollTo(0, div.scrollHeight)
|
||||||
isScrollForced = false
|
isScrollForced = false
|
||||||
@ -97,6 +112,15 @@
|
|||||||
comments = res
|
comments = res
|
||||||
newMessagesPos = newMessagesStart(comments, $lastViews)
|
newMessagesPos = newMessagesStart(comments, $lastViews)
|
||||||
notificationClient.updateLastView(id, chunter.class.Message)
|
notificationClient.updateLastView(id, chunter.class.Message)
|
||||||
|
|
||||||
|
const location = getCurrentLocation()
|
||||||
|
const messageId = location.fragment
|
||||||
|
|
||||||
|
if (messageId && location.path.length === 4) {
|
||||||
|
messageIdForScroll = messageId
|
||||||
|
location.fragment = undefined
|
||||||
|
navigate(location)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
lookup
|
lookup
|
||||||
@ -211,6 +235,7 @@
|
|||||||
<ChannelSeparator title={chunter.string.New} line reverse isNew />
|
<ChannelSeparator title={chunter.string.New} line reverse isNew />
|
||||||
{/if}
|
{/if}
|
||||||
<MsgView
|
<MsgView
|
||||||
|
isHighlighted={messageIdForScroll === comment._id && isMessageHighlighted}
|
||||||
message={comment}
|
message={comment}
|
||||||
{employees}
|
{employees}
|
||||||
thread
|
thread
|
||||||
|
@ -85,6 +85,7 @@ export default mergeIds(chunterId, chunter, {
|
|||||||
MessagesBrowser: '' as IntlString,
|
MessagesBrowser: '' as IntlString,
|
||||||
ChunterBrowser: '' as IntlString,
|
ChunterBrowser: '' as IntlString,
|
||||||
Messages: '' as IntlString,
|
Messages: '' as IntlString,
|
||||||
NoResults: '' as IntlString
|
NoResults: '' as IntlString,
|
||||||
|
CopyLink: '' as IntlString
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user