Skip to content

Commit 1d2d80c

Browse files
committed
Fade out user cursor labels after five seconds of inactivity
If we don't receive an update from a user within five seconds, hide the label of their cursor. Implementation details: * Add CSS to fade out the cursor label after five seconds per default. * Listen for Yjs updates. In case it's an awareness message, update the cursor of the author, remove the fade out CSS class and add it again after five seconds. Fixes: #4126 Signed-off-by: Jonas <jonas@freesources.org>
1 parent 2856d09 commit 1d2d80c

1 file changed

Lines changed: 43 additions & 4 deletions

File tree

src/components/Editor.vue

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ import { getCurrentUser } from '@nextcloud/auth'
8282
import { loadState } from '@nextcloud/initial-state'
8383
import { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'
8484
import { Collaboration } from '@tiptap/extension-collaboration'
85-
import { CollaborationCursor } from '@tiptap/extension-collaboration-cursor'
8685
import { Doc } from 'yjs'
86+
import debounce from 'debounce'
8787
8888
import {
8989
EDITOR,
@@ -98,7 +98,7 @@ import {
9898
import ReadonlyBar from './Menu/ReadonlyBar.vue'
9999
100100
import { logger } from '../helpers/logger.js'
101-
import { getDocumentState, applyDocumentState } from '../helpers/yjs.js'
101+
import { yjsMessageTypes, getDocumentState, applyDocumentState, getMessageType, getAwarenessMessageClientIds } from '../helpers/yjs.js'
102102
import { SyncService, ERROR_TYPE, IDLE_TIMEOUT } from './../services/SyncService.js'
103103
import createSyncServiceProvider from './../services/SyncServiceProvider.js'
104104
import AttachmentResolver from './../services/AttachmentResolver.js'
@@ -107,7 +107,7 @@ import { createEditor, serializePlainText, loadSyntaxHighlight } from './../Edit
107107
import { createMarkdownSerializer } from './../extensions/Markdown.js'
108108
import markdownit from './../markdownit/index.js'
109109
110-
import { Keymap } from './../extensions/index.js'
110+
import { CollaborationCursor, Keymap } from '../extensions/index.js'
111111
import DocumentStatus from './Editor/DocumentStatus.vue'
112112
import isMobile from './../mixins/isMobile.js'
113113
import setContent from './../mixins/setContent.js'
@@ -321,10 +321,12 @@ export default {
321321
},
322322
created() {
323323
this.$ydoc = new Doc()
324+
this.$ydoc.on('update', this.onYjsUpdate)
324325
this.$providers = []
325326
this.$editor = null
326327
this.$syncService = null
327328
this.$attachmentResolver = null
329+
this.$cursorLabelTimeouts = {}
328330
},
329331
beforeDestroy() {
330332
if (!this.richWorkspace) {
@@ -642,6 +644,35 @@ export default {
642644
this.emit('delete-image-node', imageUrl)
643645
},
644646
647+
onYjsUpdate(update, _origin, _doc, _tr) {
648+
// Update cursor labels for clients from awareness message
649+
if (getMessageType(update) === yjsMessageTypes.awareness) {
650+
if (!this.$editor) {
651+
return
652+
}
653+
654+
const clientIds = getAwarenessMessageClientIds(update)
655+
const updateUsers = this.$editor.storage.collaborationCursor.users
656+
.filter(u => clientIds.includes(u.clientId))
657+
for (const user of updateUsers) {
658+
this.updateCursorLabel(user)
659+
}
660+
}
661+
},
662+
663+
updateCursorLabel: debounce(function(user) {
664+
// Remove CSS class that fades out and hides the cursor label and bring it back after five seconds.
665+
// Limit this to once every second to prevent it from happening with each awareness update.
666+
const cursorLabelEls = document.getElementsByClassName(`collaboration-cursor__label__${user.name}`)
667+
for (const el of cursorLabelEls) {
668+
el.classList.remove('collaboration-cursor__label_fadeout')
669+
clearTimeout(this.$cursorLabelTimeouts[user.clientId])
670+
this.$cursorLabelTimeouts[user.clientId] = setTimeout(() => {
671+
el.classList.add('collaboration-cursor__label_fadeout')
672+
}, 5000)
673+
}
674+
}, 1000, true),
675+
645676
async close() {
646677
if (this.currentSession && this.$syncService) {
647678
try {
@@ -782,7 +813,6 @@ export default {
782813
width: 100%;
783814
background-color: var(--color-main-background);
784815
}
785-
786816
</style>
787817
788818
<style lang="scss">
@@ -914,4 +944,13 @@ export default {
914944
white-space: nowrap;
915945
}
916946
947+
.collaboration-cursor__label_fadeout {
948+
// transition: visibility 0s 1s, opacity 1s linear;
949+
animation: fade-out-label var(--animation-slow) forwards;
950+
}
951+
952+
@keyframes fade-out-label {
953+
0% { opacity: 1; }
954+
100% { opacity: 0; }
955+
}
917956
</style>

0 commit comments

Comments
 (0)