Skip to content

Commit

Permalink
Fade out user cursor labels after five seconds of inactivity
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
mejo- committed Jun 21, 2023
1 parent 2856d09 commit a78c3c4
Showing 1 changed file with 43 additions and 4 deletions.
47 changes: 43 additions & 4 deletions src/components/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ import { getCurrentUser } from '@nextcloud/auth'
import { loadState } from '@nextcloud/initial-state'
import { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'
import { Collaboration } from '@tiptap/extension-collaboration'
import { CollaborationCursor } from '@tiptap/extension-collaboration-cursor'
import { Doc } from 'yjs'
import debounce from 'debounce'
import {
EDITOR,
Expand All @@ -98,7 +98,7 @@ import {
import ReadonlyBar from './Menu/ReadonlyBar.vue'
import { logger } from '../helpers/logger.js'
import { getDocumentState, applyDocumentState } from '../helpers/yjs.js'
import { yjsMessageTypes, getDocumentState, applyDocumentState, getMessageType, getAwarenessMessageClientIds } from '../helpers/yjs.js'
import { SyncService, ERROR_TYPE, IDLE_TIMEOUT } from './../services/SyncService.js'
import createSyncServiceProvider from './../services/SyncServiceProvider.js'
import AttachmentResolver from './../services/AttachmentResolver.js'
Expand All @@ -107,7 +107,7 @@ import { createEditor, serializePlainText, loadSyntaxHighlight } from './../Edit
import { createMarkdownSerializer } from './../extensions/Markdown.js'
import markdownit from './../markdownit/index.js'
import { Keymap } from './../extensions/index.js'
import { CollaborationCursor, Keymap } from '../extensions/index.js'
import DocumentStatus from './Editor/DocumentStatus.vue'
import isMobile from './../mixins/isMobile.js'
import setContent from './../mixins/setContent.js'
Expand Down Expand Up @@ -321,10 +321,12 @@ export default {
},
created() {
this.$ydoc = new Doc()
this.$ydoc.on('update', this.onYjsUpdate)
this.$providers = []
this.$editor = null
this.$syncService = null
this.$attachmentResolver = null
this.$cursorLabelTimeouts = {}
},
beforeDestroy() {
if (!this.richWorkspace) {
Expand Down Expand Up @@ -642,6 +644,35 @@ export default {
this.emit('delete-image-node', imageUrl)
},
onYjsUpdate(update, _origin, _doc, _tr) {
// Update cursor labels for clients from awareness message
if (getMessageType(update) === yjsMessageTypes.awareness) {
if (!this.$editor) {
return
}
const clientIds = getAwarenessMessageClientIds(update)
const updateUsers = this.$editor.storage.collaborationCursor.users
.filter(u => clientIds.includes(u.clientId))
for (const user of updateUsers) {
this.updateCursorLabel(user)
}
}
},
updateCursorLabel: debounce(function(user) {
// Remove CSS class to fade out cursor label and add it back after five seconds.
// Limit this to once every second to prevent this from happening with each
const cursorLabelEls = document.getElementsByClassName(`collaboration-cursor__label__${user.name}`)
for (const el of cursorLabelEls) {
el.classList.remove('collaboration-cursor__label_fadeout')
clearTimeout(this.$cursorLabelTimeouts[user.clientId])
this.$cursorLabelTimeouts[user.clientId] = setTimeout(() => {
el.classList.add('collaboration-cursor__label_fadeout')
}, 5000)
}
}, 1000, true),
async close() {
if (this.currentSession && this.$syncService) {
try {
Expand Down Expand Up @@ -782,7 +813,6 @@ export default {
width: 100%;
background-color: var(--color-main-background);
}
</style>
<style lang="scss">
Expand Down Expand Up @@ -914,4 +944,13 @@ export default {
white-space: nowrap;
}
.collaboration-cursor__label_fadeout {
// transition: visibility 0s 1s, opacity 1s linear;
animation: fade-out-label var(--animation-slow) forwards;
}
@keyframes fade-out-label {
0% { opacity: 1; }
100% { opacity: 0; }
}
</style>

0 comments on commit a78c3c4

Please sign in to comment.