Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
ui: maintain menu bubble size
When selecting the right-most chars in a line
the menu bubble was getting too small.

Meassure the menu bubble when it is drawn but still hidden.
Calculate its position based on the editor width and the meassured bubble width.

Signed-off-by: Max <[email protected]>
  • Loading branch information
max-nextcloud committed Apr 5, 2022
commit 23402ca5cee86feed7cd21151794e850d7a30c7d
22 changes: 18 additions & 4 deletions src/components/EditorWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@
<slot name="header" />
</MenuBar>
<div v-if="!menubarLoaded" class="menubar placeholder" />
<MenuBubble v-if="!readOnly && isRichEditor"
:editor="tiptap"
:content-wrapper="contentWrapper"
:file-path="relativePath" />
<div ref="contentWrapper" class="content-wrapper">
<MenuBubble v-if="renderMenus"
:editor="tiptap"
:content-wrapper="contentWrapper"
:file-path="relativePath" />
<EditorContent v-show="contentLoaded"
class="editor__content"
:editor="tiptap" />
Expand Down Expand Up @@ -112,6 +112,11 @@ export default {
isMobile,
store,
],
provide() {
return {
editorInfo: this.editorInfo,
}
},
props: {
initialSession: {
type: Object,
Expand Down Expand Up @@ -176,6 +181,7 @@ export default {

saveStatusPolling: null,
contentWrapper: null,
editorInfo: { width: 640 },
}
},
computed: {
Expand Down Expand Up @@ -262,9 +268,11 @@ export default {
this.saveStatusPolling = setInterval(() => {
this.updateLastSavedStatus()
}, 2000)
window.addEventListener('resize', this.updateEditorWidth)
},
beforeDestroy() {
this.close()
window.removeEventListener('resize', this.updateEditorWidth)
},
methods: {
async close() {
Expand Down Expand Up @@ -530,6 +538,12 @@ export default {
}
}
},

updateEditorWidth() {
if (this.$el) {
this.editorInfo.width = this.$el.offsetWidth
}
},
},
}
</script>
Expand Down
23 changes: 5 additions & 18 deletions src/components/MenuBubble.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@
class="menububble"
:editor="editor"
@hide="hideLinkMenu">
<div class="menububble"
:class="{ 'is-active': menu.isActive }"
:style="bubblePosition(menu)">
<MenuBubbleContainer :menu="menu"
:class="{ 'is-active': menu.isActive }">
<form v-if="linkMenuIsActive" class="menububble__form" @submit.prevent="setLinkUrl(commands.link, linkUrl)">
<input ref="linkInput"
v-model="linkUrl"
Expand Down Expand Up @@ -59,24 +58,22 @@
<span class="menububble__buttontext">{{ t('text', 'Link file') }}</span>
</button>
</template>
</div>
</MenuBubbleContainer>
</EditorMenuBubble>
</template>

<script>
import { EditorMenuBubble } from 'tiptap'
import MenuBubbleContainer from './MenuBubbleContainer'
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip'
import { optimalPath } from './../helpers/files'
import { loadState } from '@nextcloud/initial-state'

// This is a rough estimate used for positioning the bubble.
// The actual width depends on the language and the state of the bubble.
const MAX_BUBBLE_WIDTH = 325

export default {
name: 'MenuBubble',
components: {
EditorMenuBubble,
MenuBubbleContainer,
},
directives: {
tooltip: Tooltip,
Expand Down Expand Up @@ -155,15 +152,6 @@ export default {
command({ href: url })
this.hideLinkMenu()
},
bubblePosition(menu) {
const maxLeft = document.getElementById('editor').offsetWidth - MAX_BUBBLE_WIDTH
const left = Math.min(maxLeft, menu.left - (MAX_BUBBLE_WIDTH / 2))
const offset = this.contentWrapper?.scrollTop || 0
return {
top: `${menu.top + offset + 5}px`,
left: `${left}px`,
}
},

},
}
Expand All @@ -179,7 +167,6 @@ export default {
border-radius: var(--border-radius-large);
overflow: hidden;
padding: 0;
margin-left: 10px;
visibility: hidden;
opacity: 0;
transition: opacity 0.2s, visibility 0.2s;
Expand Down
90 changes: 90 additions & 0 deletions src/components/MenuBubbleContainer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<!--
- @copyright Copyright (c) 2022 Max <[email protected]>
-
- @author Max <[email protected]>
-
- @license GNU AGPL version 3 or any later version
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-->

<template>
<div :style="bubblePosition">
<slot />
</div>
</template>

<script>

export default {
name: 'MenuBubbleContainer',

inject: ['editorInfo'],
props: {
menu: {
type: Object,
required: true,
},
isActive: {
type: Boolean,
required: false,
default: false,
},

},

data: () => {
return {
bubbleWidth: 325,
}
},

computed: {
editorWidth() {
return this.editorInfo.width
},
maxLeft() {
return this.editorWidth - this.bubbleWidth
},
bubblePosition() {
if (!this.menu.top) {
return { top: 'unset', left: 'unset' }
}
const offset = this.contentWrapper?.scrollTop || 0
const left = Math.min(this.maxLeft, this.menu.left - (this.bubbleWidth / 2))
return {
top: `${this.menu.top + offset + 5}px`,
left: `${left}px`,
}
},
},

// Meassure the bubble width once the editor is ready and visible.
// At this point the bubble will be hidden but with all content inside.
// It therefore has the width we want to use to calculate its position.
watch: {
'editorInfo.width': 'updateBubbleWidth',
},

methods: {
updateBubbleWidth() {
this.$nextTick(() => {
this.bubbleWidth = this.$el?.offsetWidth ?? 325
})
},
},

}
</script>