|
|
@@ -56,11 +56,18 @@
|
|
|
'selected': selectedSlidesIndex.includes(index),
|
|
|
}"
|
|
|
@mousedown="$event => handleClickSlideThumbnail($event, index)"
|
|
|
- @dblclick="enterScreening()"
|
|
|
- v-contextmenu="contextmenusThumbnailItem"
|
|
|
+ v-contextmenu2="contextmenusThumbnailItem"
|
|
|
>
|
|
|
+ <!-- @dblclick="enterScreening()" -->
|
|
|
<div class="label" :class="{ 'offset-left': index >= 99 }">{{ fillDigit(index + 1, 2) }}</div>
|
|
|
<ThumbnailSlide class="thumbnail" :slide="element" :size="120" :visible="index < slidesLoadLimit" />
|
|
|
+ <div class="page_menu" @click.stop="$event => showPageMenu($event, index)">
|
|
|
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <circle cx="12" cy="12" r="1"></circle>
|
|
|
+ <circle cx="12" cy="5" r="1"></circle>
|
|
|
+ <circle cx="12" cy="19" r="1"></circle>
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
|
|
|
<div class="note-flag" v-if="element.notes && element.notes.length" @click="openNotesPanel()">{{ element.notes.length }}</div>
|
|
|
</div>
|
|
|
@@ -73,7 +80,7 @@
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
-import { computed, nextTick, ref, watch, useTemplateRef } from 'vue'
|
|
|
+import { computed, nextTick, ref, watch, useTemplateRef, createVNode, render } from 'vue'
|
|
|
import { storeToRefs } from 'pinia'
|
|
|
import { useMainStore, useSlidesStore, useKeyboardStore } from '@/store'
|
|
|
import { fillDigit } from '@/utils/common'
|
|
|
@@ -90,6 +97,7 @@ import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
|
|
|
import Templates from './Templates.vue'
|
|
|
import Popover from '@/components/Popover.vue'
|
|
|
import Draggable from 'vuedraggable'
|
|
|
+import ContextmenuComponent from '@/components/Contextmenu2/index.vue'
|
|
|
|
|
|
// 检测是否为移动设备(包括iPad和手机)
|
|
|
const isMobileDevice = computed(() => {
|
|
|
@@ -315,55 +323,100 @@ const contextmenusThumbnails = (): ContextmenuItem[] => {
|
|
|
]
|
|
|
}
|
|
|
|
|
|
+const showPageMenu = (event: MouseEvent, index: number) => {
|
|
|
+ event.stopPropagation()
|
|
|
+
|
|
|
+ const menus = contextmenusThumbnailItem()
|
|
|
+ if (!menus) return
|
|
|
+
|
|
|
+ let container: HTMLDivElement | null = null
|
|
|
+
|
|
|
+ const removeContextmenu = () => {
|
|
|
+ if (container) {
|
|
|
+ document.body.removeChild(container)
|
|
|
+ container = null
|
|
|
+ }
|
|
|
+ document.body.removeEventListener('scroll', removeContextmenu)
|
|
|
+ window.removeEventListener('resize', removeContextmenu)
|
|
|
+ }
|
|
|
+
|
|
|
+ const options = {
|
|
|
+ axis: { x: event.clientX - 20, y: event.clientY - 20 },
|
|
|
+ el: event.currentTarget as HTMLElement,
|
|
|
+ menus,
|
|
|
+ removeContextmenu,
|
|
|
+ }
|
|
|
+ container = document.createElement('div')
|
|
|
+ const vm = createVNode(ContextmenuComponent, options, null)
|
|
|
+ render(vm, container)
|
|
|
+ document.body.appendChild(container)
|
|
|
+
|
|
|
+ document.body.addEventListener('scroll', removeContextmenu)
|
|
|
+ window.addEventListener('resize', removeContextmenu)
|
|
|
+}
|
|
|
+
|
|
|
const contextmenusThumbnailItem = (): ContextmenuItem[] => {
|
|
|
return [
|
|
|
+ // {
|
|
|
+ // text: lang.ssCut,
|
|
|
+ // subText: 'Ctrl + X',
|
|
|
+ // handler: cutSlide,
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // text: lang.ssCopy,
|
|
|
+ // subText: 'Ctrl + C',
|
|
|
+ // handler: copySlide,
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // text: lang.ssPaste,
|
|
|
+ // subText: 'Ctrl + V',
|
|
|
+ // handler: pasteSlide,
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // text: lang.ssSelectAll,
|
|
|
+ // subText: 'Ctrl + A',
|
|
|
+ // handler: selectAllSlide,
|
|
|
+ // },
|
|
|
+ // { divider: true },
|
|
|
+ // {
|
|
|
+ // text: lang.ssNewPage,
|
|
|
+ // subText: 'Enter',
|
|
|
+ // handler: createSlide,
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // text: lang.ssDupPage,
|
|
|
+ // subText: 'Ctrl + D',
|
|
|
+ // handler: copyAndPasteSlide,
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // text: lang.ssDelPage,
|
|
|
+ // subText: 'Delete',
|
|
|
+ // handler: () => deleteSlide(),
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // text: lang.ssAddSect,
|
|
|
+ // handler: createSection,
|
|
|
+ // disable: !!currentSlide.value.sectionTag,
|
|
|
+ // },
|
|
|
+ // { divider: true },
|
|
|
+ // {
|
|
|
+ // text: lang.ssPlayFromCur,
|
|
|
+ // subText: 'Shift + F5',
|
|
|
+ // handler: enterScreening,
|
|
|
+ // },
|
|
|
+
|
|
|
{
|
|
|
- text: lang.ssCut,
|
|
|
- subText: 'Ctrl + X',
|
|
|
- handler: cutSlide,
|
|
|
- },
|
|
|
- {
|
|
|
- text: lang.ssCopy,
|
|
|
- subText: 'Ctrl + C',
|
|
|
- handler: copySlide,
|
|
|
- },
|
|
|
- {
|
|
|
- text: lang.ssPaste,
|
|
|
- subText: 'Ctrl + V',
|
|
|
- handler: pasteSlide,
|
|
|
- },
|
|
|
- {
|
|
|
- text: lang.ssSelectAll,
|
|
|
- subText: 'Ctrl + A',
|
|
|
- handler: selectAllSlide,
|
|
|
+ text: lang.ssDupPage2,
|
|
|
+ handler: copyAndPasteSlide,
|
|
|
},
|
|
|
- { divider: true },
|
|
|
{
|
|
|
- text: lang.ssNewPage,
|
|
|
- subText: 'Enter',
|
|
|
+ text: lang.ssNewPage2,
|
|
|
handler: createSlide,
|
|
|
},
|
|
|
{
|
|
|
- text: lang.ssDupPage,
|
|
|
- subText: 'Ctrl + D',
|
|
|
- handler: copyAndPasteSlide,
|
|
|
- },
|
|
|
- {
|
|
|
- text: lang.ssDelPage,
|
|
|
- subText: 'Delete',
|
|
|
+ text: lang.ssDelPage2,
|
|
|
handler: () => deleteSlide(),
|
|
|
},
|
|
|
- {
|
|
|
- text: lang.ssAddSect,
|
|
|
- handler: createSection,
|
|
|
- disable: !!currentSlide.value.sectionTag,
|
|
|
- },
|
|
|
- { divider: true },
|
|
|
- {
|
|
|
- text: lang.ssPlayFromCur,
|
|
|
- subText: 'Shift + F5',
|
|
|
- handler: enterScreening,
|
|
|
- },
|
|
|
]
|
|
|
}
|
|
|
</script>
|
|
|
@@ -490,6 +543,10 @@ const contextmenusThumbnailItem = (): ContextmenuItem[] => {
|
|
|
color: #999;
|
|
|
width: 20px;
|
|
|
cursor: grab;
|
|
|
+ position: absolute;
|
|
|
+ z-index: 999;
|
|
|
+ top: 10px;
|
|
|
+ left: 10px;
|
|
|
|
|
|
&.offset-left {
|
|
|
position: relative;
|
|
|
@@ -500,6 +557,39 @@ const contextmenusThumbnailItem = (): ContextmenuItem[] => {
|
|
|
cursor: grabbing;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+.page_menu{
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ cursor: pointer;
|
|
|
+ position: absolute;
|
|
|
+ z-index: 999;
|
|
|
+ bottom: 10px;
|
|
|
+ right: 10px;
|
|
|
+ background: rgba(255, 255, 255, 0.95);
|
|
|
+ border: 1px solid #e5e7eb;
|
|
|
+ transition: .3s;
|
|
|
+ border-radius: 5px;
|
|
|
+
|
|
|
+ svg{
|
|
|
+ color: #6b7280;
|
|
|
+ height: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .active,
|
|
|
+ &:hover{
|
|
|
+ border-color: $themeColor2;
|
|
|
+ background-color: $themeColor2;
|
|
|
+
|
|
|
+ svg{
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
.page-number {
|
|
|
/* height: 100%; */
|
|
|
font-size: 12px;
|