Skip to content

Commit

Permalink
为部分菜单增加图标
Browse files Browse the repository at this point in the history
更换右键菜单组件以更好的支持响应式框架
支持使用 Command 快捷键
  • Loading branch information
Steve-xmh committed Feb 9, 2024
1 parent 782125f commit fbc9518
Show file tree
Hide file tree
Showing 4 changed files with 641 additions and 531 deletions.
173 changes: 117 additions & 56 deletions src/components/ContextMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,84 +10,145 @@
-->

<template>
<NDropdown trigger="manual" :show="lyricLineMenu.show" @select="onSelectMenu" :x="lyricLineMenu.x"
:y="lyricLineMenu.y"
placement="bottom-start"
:options="lyricLineMenu.selectedWord === -1 ? lineContextMenu : wordOnlyContextMenu"
@clickoutside="lyricLineMenu.show = false"/>
<NPopover :arrow="false" :options="lyricLineMenu.selectedWord === -1 ? lineContextMenu : wordOnlyContextMenu" :show="lyricLineMenu.show"
:x="lyricLineMenu.x"
:y="lyricLineMenu.y"
class="context-menu"
placement="bottom-start"
style="padding: 4px"
trigger="manual"
@clickoutside="lyricLineMenu.show = false">
<ContextMenuWordEdit/>
<NEl tag="button"
@click="() => {lyric.removeWord(lyricLineMenu.selectedLine, lyricLineMenu.selectedWord); lyricLineMenu.show = false;}">
<i18n-t keypath="contextMenu.deleteWord"/>
</NEl>
<NEl tag="button" @click="showWipNotification">
<i18n-t keypath="contextMenu.splitWord"/>
</NEl>
<NDivider style="margin: 4px 0"/>
<NEl tag="button" @click="() => {lyric.removeLine(lyricLineMenu.selectedLine); lyricLineMenu.show = false;}">
<i18n-t keypath="contextMenu.deleteLine"/>
</NEl>
<NEl tag="button" @click="() => {lyric.insertNewLineAt(lyricLineMenu.selectedLine); lyricLineMenu.show = false;}">
<i18n-t keypath="contextMenu.insertBeforeLine"/>
</NEl>
<NEl tag="button"
@click="() => {lyric.insertNewLineAt(lyricLineMenu.selectedLine + 1); lyricLineMenu.show = false;}">
<i18n-t keypath="contextMenu.insertAfterLine"/>
</NEl>
<NEl tag="button"
@click="() => { const line = lyric.lyrics[lyricLineMenu.selectedLine]; if (line) line.isBG = !line.isBG; lyricLineMenu.show = false; }">
<i18n-t keypath="contextMenu.toggleBGLine"/>
</NEl>
<NEl tag="button"
@click="() => { const line = lyric.lyrics[lyricLineMenu.selectedLine]; if (line) line.isDuet = !line.isDuet; lyricLineMenu.show = false; }">
<i18n-t keypath="contextMenu.toggleDuetLine"/>
</NEl>
</NPopover>
</template>

<script setup lang="tsx">
import {NDropdown, useNotification} from "naive-ui";
import {NDivider, NEl, NPopover, useNotification} from "naive-ui";
import {onMounted} from "vue";
import {useEditingLyric, useRightClickLyricLine} from "../store";
import type {DropdownMixedOption} from "naive-ui/es/dropdown/src/interface";
import {i18n} from '../i18n';
import ContextMenuWordEdit from "./ContextMenuWordEdit.vue";
const lineContextMenu = [
{label: i18n.global.t("contextMenu.deleteLine"), key: 'delete-line'},
{label: i18n.global.t("contextMenu.insertBeforeLine"), key: 'insert-before-line'},
{label: i18n.global.t("contextMenu.insertAfterLine"), key: 'insert-after-line'},
{label: i18n.global.t("contextMenu.toggleBGLine"), key: 'toggle-bg-line'},
{label: i18n.global.t("contextMenu.toggleDuetLine"), key: 'toggle-duet-line'},
{label: i18n.global.t("contextMenu.deleteLine"), key: 'delete-line'},
{label: i18n.global.t("contextMenu.insertBeforeLine"), key: 'insert-before-line'},
{label: i18n.global.t("contextMenu.insertAfterLine"), key: 'insert-after-line'},
{label: i18n.global.t("contextMenu.toggleBGLine"), key: 'toggle-bg-line'},
{label: i18n.global.t("contextMenu.toggleDuetLine"), key: 'toggle-duet-line'},
] as DropdownMixedOption[];
const wordOnlyContextMenu = [
{type: "render", render: () => <ContextMenuWordEdit/>},
{label: i18n.global.t("contextMenu.deleteWord"), key: 'delete-word'},
{label: i18n.global.t("contextMenu.splitWord"), key: 'split-word'},
{type: 'divider',},
...lineContextMenu
{type: "render", render: () => <ContextMenuWordEdit/>},
{label: i18n.global.t("contextMenu.deleteWord"), key: 'delete-word'},
{label: i18n.global.t("contextMenu.splitWord"), key: 'split-word'},
{type: 'divider',},
...lineContextMenu
] as DropdownMixedOption[];
const lyricLineMenu = useRightClickLyricLine();
const notify = useNotification();
const lyric = useEditingLyric();
function showWipNotification() {
notify.error({
title: i18n.global.t("contextMenu.wipNotification.title"),
content: i18n.global.t("contextMenu.wipNotification.content"),
duration: 4000,
});
lyricLineMenu.show = false;
}
function onSelectMenu(key: string) {
switch (key) {
case "delete-line": {
lyric.removeLine(lyricLineMenu.selectedLine);
break;
}
case "delete-word": {
lyric.removeWord(lyricLineMenu.selectedLine, lyricLineMenu.selectedWord);
break;
}
case "toggle-bg-line": {
const line = lyric.lyrics[lyricLineMenu.selectedLine];
if (line) line.isBG = !line.isBG;
break;
}
case "toggle-duet-line": {
const line = lyric.lyrics[lyricLineMenu.selectedLine];
if (line) line.isDuet = !line.isDuet;
break;
}
case "insert-before-line": {
lyric.insertNewLineAt(lyricLineMenu.selectedLine);
break;
}
case "insert-after-line": {
lyric.insertNewLineAt(lyricLineMenu.selectedLine + 1);
break;
}
default: {
notify.error({
title: i18n.global.t("contextMenu.wipNotification.title"),
content: i18n.global.t("contextMenu.wipNotification.content"),
duration: 4000,
});
}
switch (key) {
case "delete-line": {
lyric.removeLine(lyricLineMenu.selectedLine);
break;
}
case "delete-word": {
lyric.removeWord(lyricLineMenu.selectedLine, lyricLineMenu.selectedWord);
break;
}
case "toggle-bg-line": {
const line = lyric.lyrics[lyricLineMenu.selectedLine];
if (line) line.isBG = !line.isBG;
break;
}
case "toggle-duet-line": {
const line = lyric.lyrics[lyricLineMenu.selectedLine];
if (line) line.isDuet = !line.isDuet;
break;
}
case "insert-before-line": {
break;
}
lyricLineMenu.show = false;
case "insert-after-line": {
break;
}
default: {
notify.error({
title: i18n.global.t("contextMenu.wipNotification.title"),
content: i18n.global.t("contextMenu.wipNotification.content"),
duration: 4000,
});
}
}
}
onMounted(() => {
// ask before page close
window.addEventListener("beforeunload", evt => {
evt.preventDefault();
return evt.returnValue = "";
})
// ask before page close
window.addEventListener("beforeunload", evt => {
evt.preventDefault();
return evt.returnValue = "";
})
});
</script>

<style lang="sass" scoped>
.context-menu
button
display: block
width: 100%
text-align: left
border-radius: var(--border-radius-small)
font-family: var(--font-family)
font-size: var(--font-size)
color: var(--text-color-base)
background-color: transparent
border: none
transition: background-color 0.2s ease-in-out
cursor: pointer
padding: 0.5em 1em
margin-top: 2px
&:hover
background-color: var(--button-color-2-hover)
</style>
45 changes: 23 additions & 22 deletions src/components/ContextMenuWordEdit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
-->

<template>
<div class="context-menu-word-edit">
<div>内容</div>
<NInput @blur="onContentBlur" placeholder="" v-model:value="wordEdit.word" size="small"/>
<div>空拍</div>
<NInputNumber v-model:value="wordEdit.emptyBeat" @blur="onEmptyBeatBlur"
style="max-width: 7em" placeholder="0" :min="0" :step="1" size="small"/>
</div>
<div class="context-menu-word-edit">
<div>内容</div>
<NInput v-model:value="wordEdit.word" placeholder="" size="small" @blur="onContentBlur"/>
<div>空拍</div>
<NInputNumber v-model:value="wordEdit.emptyBeat" :min="0"
:step="1" placeholder="0" size="small" style="max-width: 7em" @blur="onEmptyBeatBlur"/>
</div>
</template>

<script setup lang="ts">
Expand All @@ -31,37 +31,38 @@ const notify = useNotification();
const lyric = useEditingLyric();
const wordEdit = reactive({
word: "",
emptyBeat: 0,
word: "",
emptyBeat: 0,
})
onMounted(() => {
const selectedWord: LyricWord | undefined = lyric.lyrics[lyricLineMenu.selectedLine]?.words?.[lyricLineMenu.selectedWord];
const selectedWord: LyricWord | undefined = lyric.lyrics[lyricLineMenu.selectedLine]?.words?.[lyricLineMenu.selectedWord];
wordEdit.word = selectedWord?.word ?? "";
wordEdit.emptyBeat = selectedWord?.emptyBeat ?? 0;
wordEdit.word = selectedWord?.word ?? "";
wordEdit.emptyBeat = selectedWord?.emptyBeat ?? 0;
})
function onEmptyBeatBlur() {
lyric.modifyWordEmptyBeat(lyricLineMenu.selectedLine, lyricLineMenu.selectedWord, wordEdit.emptyBeat);
lyric.modifyWordEmptyBeat(lyricLineMenu.selectedLine, lyricLineMenu.selectedWord, wordEdit.emptyBeat);
}
function onContentBlur() {
lyric.modifyWord(lyricLineMenu.selectedLine, lyricLineMenu.selectedWord, wordEdit.word);
lyric.modifyWord(lyricLineMenu.selectedLine, lyricLineMenu.selectedWord, wordEdit.word);
}
</script>

<style scoped lang="sass">
.context-menu-word-edit
width: 100%
padding: 8px 14px
display: grid
grid-template-columns: auto auto
gap: 8px
align-items: center
width: 100%
display: grid
padding: 0 1em
padding-top: 0.5em
grid-template-columns: auto auto
gap: 8px
align-items: center
> *:nth-child(2n)
justify-self: flex-end
> *:nth-child(2n)
justify-self: flex-end
</style>

14 changes: 7 additions & 7 deletions src/components/LyricEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@
</template>

<script setup lang="tsx">
import { NButton } from "naive-ui";
import { useEditingLyric, useRightClickLyricLine, useSettings } from "../store";
import {NButton} from "naive-ui";
import {useEditingLyric, useRightClickLyricLine, useSettings} from "../store";
import LyricLineEditor from "./LyricLineEditor.vue";
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller'
import { onMounted, onUnmounted } from "vue";
import {DynamicScroller, DynamicScrollerItem} from 'vue-virtual-scroller'
import {onMounted, onUnmounted} from "vue";
const settings = useSettings();
Expand All @@ -61,17 +61,17 @@ function onAddNewLine() {
}
function onKeyPress(e: KeyboardEvent) {
if (e.ctrlKey && e.code === "KeyZ") {
if ((e.ctrlKey || e.metaKey) && e.code === "KeyZ") {
lyric.undo();
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
} else if (e.ctrlKey && e.code === "KeyY") {
} else if ((e.ctrlKey || e.metaKey) && e.code === "KeyY") {
lyric.redo();
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
} else if (e.ctrlKey && e.code === "KeyA") {
} else if ((e.ctrlKey || e.metaKey) && e.code === "KeyA") {
lyric.selectAllLine();
e.preventDefault();
e.stopPropagation();
Expand Down

0 comments on commit fbc9518

Please sign in to comment.