feat(all): add sub-setting
This commit is contained in:
8
components.d.ts
vendored
8
components.d.ts
vendored
@@ -13,24 +13,32 @@ declare module 'vue' {
|
||||
ChapterList: typeof import('./src/components/ChapterList.vue')['default']
|
||||
DictList: typeof import('./src/components/DictList.vue')['default']
|
||||
DictModal: typeof import('./src/components/Toolbar/DictModal.vue')['default']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
||||
ElProgress: typeof import('element-plus/es')['ElProgress']
|
||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElSlider: typeof import('element-plus/es')['ElSlider']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
FeedbackModal: typeof import('./src/components/Toolbar/FeedbackModal.vue')['default']
|
||||
Fireworks: typeof import('./src/components/Fireworks.vue')['default']
|
||||
Footer: typeof import('./src/components/Practice/Footer.vue')['default']
|
||||
IconWrapper: typeof import('./src/components/IconWrapper.vue')['default']
|
||||
MiniModal: typeof import('./src/components/MiniModal.vue')['default']
|
||||
Modal: typeof import('./src/components/Modal/Modal.vue')['default']
|
||||
PopConfirm: typeof import('./src/components/PopConfirm.vue')['default']
|
||||
Practice: typeof import('./src/components/Practice/Practice.vue')['default']
|
||||
RepeatSetting: typeof import('./src/components/Toolbar/RepeatSetting.vue')['default']
|
||||
Ring: typeof import('./src/components/Ring.vue')['default']
|
||||
SettingModal: typeof import('./src/components/Toolbar/SettingModal.vue')['default']
|
||||
Side: typeof import('./src/components/Side.vue')['default']
|
||||
Statistics: typeof import('./src/components/Modal/Statistics.vue')['default']
|
||||
Toolbar: typeof import('./src/components/Toolbar/Toolbar.vue')['default']
|
||||
Tooltip: typeof import('./src/components/Tooltip.vue')['default']
|
||||
TrabslateSetting: typeof import('./src/components/Toolbar/TrabslateSetting.vue')['default']
|
||||
TypeArticle: typeof import('./src/components/Practice/TypeArticle.vue')['default']
|
||||
TypeWord: typeof import('./src/components/Practice/TypeWord.vue')['default']
|
||||
VolumeSetting: typeof import('./src/components/Toolbar/VolumeSetting.vue')['default']
|
||||
WordList: typeof import('./src/components/WordList.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ export default {
|
||||
render() {
|
||||
let Vnode = this.$slots.default()[0]
|
||||
return (
|
||||
<div class="icon-wrapper hvr-grow">
|
||||
<div class="icon-wrapper ">
|
||||
<Vnode
|
||||
/>
|
||||
</div>
|
||||
@@ -17,9 +17,9 @@ export default {
|
||||
|
||||
$w: 20rem;
|
||||
.icon-wrapper {
|
||||
padding: 2rem;
|
||||
//width: 24rem;
|
||||
//height: 24rem;
|
||||
//padding: 2rem;
|
||||
width: 26rem;
|
||||
height: 26rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
44
src/components/MiniModal.vue
Normal file
44
src/components/MiniModal.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<script setup lang="ts">
|
||||
interface IProps {
|
||||
modelValue?: boolean,
|
||||
}
|
||||
|
||||
withDefaults(defineProps<IProps>(), {
|
||||
modelValue: true,
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Transition name="fade">
|
||||
<div v-if="modelValue" class="mini-modal">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "@/assets/css/style";
|
||||
|
||||
.mini-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: $space;
|
||||
color: black;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.mini-modal {
|
||||
position: absolute;
|
||||
z-index: 9;
|
||||
width: 180rem;
|
||||
background: white;
|
||||
border-radius: 8rem;
|
||||
box-shadow: 1px 1px 6px #bbbbbb;
|
||||
padding: 10rem $space;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
margin-top: 10rem;
|
||||
}
|
||||
</style>
|
||||
@@ -23,7 +23,7 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
function write() {
|
||||
store.isDictation = true
|
||||
store.setting.dictation = true
|
||||
repeat()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {Icon} from '@iconify/vue'
|
||||
import {usePlayWordAudio} from "@/hooks/usePlayWordAudio.ts"
|
||||
import {computed, nextTick, onMounted, reactive, watch} from "vue"
|
||||
import {cloneDeep} from "lodash-es"
|
||||
@@ -28,16 +28,13 @@ import {
|
||||
Word
|
||||
} from "@/types";
|
||||
import {useBaseStore} from "@/stores/base";
|
||||
import Footer from "@/components/Practice/Footer.vue"
|
||||
import {usePracticeStore} from "@/components/Practice/usePracticeStore.ts";
|
||||
import {useEventListener} from "@/hooks/useEvent.ts";
|
||||
import TypeWord from "@/components/Practice/TypeWord.vue";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
import Baidu from "@opentranslate/baidu";
|
||||
import {axiosInstance} from "@/utils/http";
|
||||
import {translate} from "element-plus";
|
||||
import useSleep from "@/hooks/useSleep.ts";
|
||||
import {useLocalTranslate, useNetworkTranslate} from "@/hooks/translate.ts";
|
||||
import IconWrapper from "@/components/IconWrapper.vue";
|
||||
import Tooltip from "@/components/Tooltip.vue";
|
||||
import MiniModal from "@/components/MiniModal.vue";
|
||||
|
||||
let article1 = `How does the older investor differ in his approach to investment from the younger investor?
|
||||
There is no shortage of tipsters around offering 'get-rich-quick' opportunities. But if you are a serious private investor, leave the Las Vegas mentality to those with money to fritter. The serious investor needs a proper 'portfolio' -- a well-planned selection of investments, with a definite structure and a clear aim. But exactly how does a newcomer to the stock market go about achieving that?
|
||||
@@ -85,9 +82,7 @@ let stringIndex = $ref(0)
|
||||
let input = $ref('')
|
||||
let wrong = $ref('')
|
||||
let isSpace = $ref(false)
|
||||
let isDictation = $ref(true)
|
||||
let showTranslate = $ref(true)
|
||||
let showFullWord = $ref(false)
|
||||
let hoverIndex = $ref({
|
||||
sectionIndex: -1,
|
||||
sentenceIndex: -1,
|
||||
@@ -204,7 +199,7 @@ function onKeyDown(e: KeyboardEvent) {
|
||||
sentenceIndex = 0
|
||||
sectionIndex++
|
||||
} else {
|
||||
if (isDictation) {
|
||||
if (store.setting.dictation) {
|
||||
calcTranslateLocation()
|
||||
}
|
||||
playAudio(currentSection[sentenceIndex].sentence)
|
||||
@@ -328,8 +323,8 @@ function onKeyUp() {
|
||||
}
|
||||
}
|
||||
|
||||
useEventListener('keydown', onKeyDown)
|
||||
useEventListener('keyup', onKeyUp)
|
||||
// useEventListener('keydown', onKeyDown)
|
||||
// useEventListener('keyup', onKeyUp)
|
||||
|
||||
function playWord(word: ArticleWord) {
|
||||
playAudio(word.name)
|
||||
@@ -344,7 +339,7 @@ function currentWordInput(word: ArticleWord, i: number, i2: number,) {
|
||||
return str
|
||||
}
|
||||
|
||||
if (isDictation) {
|
||||
if (store.setting.dictation) {
|
||||
return '_'
|
||||
}
|
||||
return str
|
||||
@@ -356,7 +351,7 @@ function currentWordEnd(word: ArticleWord, i: number, i2: number,) {
|
||||
return str
|
||||
}
|
||||
|
||||
if (isDictation) {
|
||||
if (store.setting.dictation) {
|
||||
return str.split('').map(v => '_').join('')
|
||||
}
|
||||
return str
|
||||
@@ -374,7 +369,7 @@ function otherWord(word: ArticleWord, i: number, i2: number, i3: number) {
|
||||
|
||||
//剩100是因为,可能存在特殊情况,比如003,010这种,0 12 24,100
|
||||
if (sectionIndex * 10000 + sentenceIndex * 100 + wordIndex < i * 10000 + i2 * 100 + i3
|
||||
&& isDictation
|
||||
&& store.setting.dictation
|
||||
) {
|
||||
return str.split('').map(v => '_').join('')
|
||||
}
|
||||
@@ -391,17 +386,6 @@ function otherWord(word: ArticleWord, i: number, i2: number, i3: number) {
|
||||
<div class="article-wrapper">
|
||||
<header>
|
||||
<div class="title">A private conversation!</div>
|
||||
<div class="options">
|
||||
<el-progress :percentage="80"
|
||||
:stroke-width="8"
|
||||
:show-text="false"/>
|
||||
|
||||
<div class="translate-btn">
|
||||
<div>翻译</div>
|
||||
<div>本地</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</header>
|
||||
<div class="article-content" ref="articleWrapperRef">
|
||||
<article>
|
||||
@@ -409,7 +393,7 @@ function otherWord(word: ArticleWord, i: number, i2: number, i3: number) {
|
||||
v-for="(section,indexI) in article.sections">
|
||||
<span class="sentence"
|
||||
:class="[
|
||||
sectionIndex === indexI && sentenceIndex === indexJ && isDictation
|
||||
sectionIndex === indexI && sentenceIndex === indexJ && store.setting.dictation
|
||||
?'dictation':''
|
||||
]"
|
||||
@mouseenter="hoverIndex = {sectionIndex : indexI,sentenceIndex :indexJ}"
|
||||
@@ -445,9 +429,11 @@ function otherWord(word: ArticleWord, i: number, i2: number, i3: number) {
|
||||
`${indexI}${indexJ}${indexW}`,
|
||||
(`${indexI}${indexJ}${indexW}` === currentIndex && isSpace && wrong) && 'bg-wrong',
|
||||
(`${indexI}${indexJ}${indexW}` === currentIndex && isSpace && !wrong) && 'bottom-border',
|
||||
(`${indexI}${indexJ}${indexW}` === currentIndex && isSpace && !wrong && isDictation) && 'word-space',
|
||||
(`${indexI}${indexJ}${indexW}` === currentIndex && isSpace && !wrong && store.setting.dictation) && 'word-space',
|
||||
]">
|
||||
{{ (`${indexI}${indexJ}${indexW}` === currentIndex && isSpace && isDictation) ? '_' : ' ' }}
|
||||
{{
|
||||
(`${indexI}${indexJ}${indexW}` === currentIndex && isSpace && store.setting.dictation) ? '_' : ' '
|
||||
}}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
@@ -500,7 +486,6 @@ function otherWord(word: ArticleWord, i: number, i2: number, i3: number) {
|
||||
}
|
||||
|
||||
.article-wrapper {
|
||||
opacity: 0;
|
||||
|
||||
header {
|
||||
.title {
|
||||
@@ -511,21 +496,6 @@ function otherWord(word: ArticleWord, i: number, i2: number, i3: number) {
|
||||
word-spacing: 3rem;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
gap:20rem;
|
||||
|
||||
.el-progress {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.translate-btn {
|
||||
color:black;
|
||||
font-size: 20rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.article-content {
|
||||
|
||||
@@ -204,7 +204,7 @@ async function onKeyDown(e: KeyboardEvent) {
|
||||
<div class="word" :class="wrong && 'is-wrong'">
|
||||
<span class="input" v-if="input">{{ input }}</span>
|
||||
<span class="wrong" v-if="wrong">{{ wrong }}</span>
|
||||
<template v-if="store.isDictation">
|
||||
<template v-if="store.setting.dictation">
|
||||
<span class="letter" v-if="!showFullWord"
|
||||
@mouseenter="showFullWord = true">{{ resetWord.split('').map(v => '_').join('') }}</span>
|
||||
<span class="letter" v-else @mouseleave="showFullWord = false">{{ resetWord }}</span>
|
||||
|
||||
74
src/components/Toolbar/RepeatSetting.vue
Normal file
74
src/components/Toolbar/RepeatSetting.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import MiniModal from "@/components/MiniModal.vue";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import IconWrapper from "@/components/IconWrapper.vue";
|
||||
import Tooltip from "@/components/Tooltip.vue";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {useWindowClick} from "@/hooks/event.ts";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
import {onMounted} from "vue";
|
||||
|
||||
const store = useBaseStore()
|
||||
let show = $ref(false)
|
||||
let radio1 = $ref('1')
|
||||
useWindowClick(() => show = false)
|
||||
|
||||
function toggle() {
|
||||
if (!show) emitter.emit(EventKey.closeOther)
|
||||
show = !show
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="setting" @click.stop="null">
|
||||
<Tooltip title="单词循环设置">
|
||||
<IconWrapper>
|
||||
<Icon icon="tabler:repeat"
|
||||
@click="toggle"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<MiniModal
|
||||
v-model="show"
|
||||
style="width: 230rem;"
|
||||
>
|
||||
<div class="title">选择单词的循环次数</div>
|
||||
<el-radio-group v-model="store.setting.repeatCount">
|
||||
<el-radio :label="1" size="default">1</el-radio>
|
||||
<el-radio :label="2" size="default">2</el-radio>
|
||||
<el-radio :label="3" size="default">3</el-radio>
|
||||
<el-radio :label="5" size="default">5</el-radio>
|
||||
<el-radio :label="100" size="default">自定义</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="mini-row" v-if="store.setting.repeatCount === 100">
|
||||
<label class="item-title">自定义循环次数</label>
|
||||
<el-input-number v-model="store.setting.repeatCustomCount"
|
||||
:min="6"
|
||||
:max="100"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</MiniModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/style";
|
||||
|
||||
.setting {
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.el-radio-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -11,6 +11,8 @@ import {Icon} from '@iconify/vue';
|
||||
import IconWrapper from "@/components/IconWrapper.vue";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts"
|
||||
import {watch} from "vue"
|
||||
import VolumeSetting from "@/components/Toolbar/VolumeSetting.vue";
|
||||
import RepeatSetting from "@/components/Toolbar/RepeatSetting.vue";
|
||||
|
||||
const {toggle} = useTheme()
|
||||
const store = useBaseStore()
|
||||
@@ -33,70 +35,77 @@ watch(() => store.setting.showToolbar, n => {
|
||||
|
||||
<template>
|
||||
<header ref="headerRef">
|
||||
<div class="info" @click="showDictModal = true">
|
||||
{{ store.dictTitle }}
|
||||
<div class="content">
|
||||
<div class="info" @click="showDictModal = true">
|
||||
{{ store.dictTitle }}
|
||||
</div>
|
||||
<div class="options">
|
||||
<Tooltip title="切换主题">
|
||||
<IconWrapper>
|
||||
<Icon icon="ep:moon" v-if="store.theme === 'dark'"
|
||||
@click="toggle"/>
|
||||
<Icon icon="tabler:sun" v-else @click="toggle"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
|
||||
<VolumeSetting/>
|
||||
|
||||
<RepeatSetting/>
|
||||
|
||||
<Tooltip title="开关默写模式">
|
||||
<IconWrapper>
|
||||
<Icon icon="majesticons:eye-off-line"
|
||||
v-if="store.setting.dictation"
|
||||
@click="store.setting.dictation = false"/>
|
||||
<Icon icon="mdi:eye-outline"
|
||||
v-else
|
||||
@click="store.setting.dictation = true"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="开关释义显示">
|
||||
<IconWrapper>
|
||||
<Icon icon="heroicons-outline:translate"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="反馈">
|
||||
<IconWrapper>
|
||||
<Icon icon="ic:outline-cloud-upload"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="反馈">
|
||||
<IconWrapper>
|
||||
<Icon icon="octicon:bug-24" @click="showFeedbackModal = true"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="设置">
|
||||
<IconWrapper>
|
||||
<Icon icon="uil:setting" @click="showSettingModal = true"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<div class="my-button" @click="emitter.emit(EventKey.openStatModal)">ok</div>
|
||||
|
||||
<Tooltip title="单词本">
|
||||
<IconWrapper>
|
||||
<Icon icon="tdesign:menu-unfold" class="menu" @click="emitter.emit(EventKey.openSide)"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options">
|
||||
<Tooltip title="切换主题">
|
||||
<IconWrapper>
|
||||
<Icon icon="ep:moon" v-if="store.theme === 'dark'"
|
||||
@click="toggle"/>
|
||||
<Icon icon="tabler:sun" v-else @click="toggle"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="音效设置">
|
||||
<IconWrapper>
|
||||
<Icon icon="icon-park-outline:volume-notice"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="设置单词循环">
|
||||
<IconWrapper>
|
||||
<Icon icon="tabler:repeat"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="开关默写模式">
|
||||
<IconWrapper>
|
||||
<Icon icon="majesticons:eye-off-line" v-if="store.isDictation" @click="store.isDictation = false"/>
|
||||
<Icon icon="mdi:eye-outline" v-else @click="store.isDictation = true"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="开关释义显示">
|
||||
<IconWrapper>
|
||||
<Icon icon="heroicons-outline:translate"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="反馈">
|
||||
<IconWrapper>
|
||||
<Icon icon="ic:outline-cloud-upload"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="反馈">
|
||||
<IconWrapper>
|
||||
<Icon icon="octicon:bug-24" @click="showFeedbackModal = true"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="设置">
|
||||
<IconWrapper>
|
||||
<Icon icon="uil:setting" @click="showSettingModal = true"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<div class="my-button" @click="emitter.emit(EventKey.openStatModal)">ok</div>
|
||||
|
||||
<Tooltip title="单词本">
|
||||
<IconWrapper>
|
||||
<Icon icon="tdesign:menu-unfold" class="menu" @click="emitter.emit(EventKey.openSide)"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<div class="translate-progress">
|
||||
<div>翻译进度:</div>
|
||||
<el-progress :percentage="80"
|
||||
:stroke-width="8"
|
||||
:show-text="false"/>
|
||||
</div>
|
||||
<Tooltip :title="store.setting.showToolbar?'收起':'展开'">
|
||||
<Icon icon="icon-park-outline:down"
|
||||
@click="store.setting.showToolbar = !store.setting.showToolbar"
|
||||
class="arrow"
|
||||
:class="!store.setting.showToolbar && 'down'"
|
||||
width="24" color="#999"/>
|
||||
width="24"
|
||||
color="#999"/>
|
||||
</Tooltip>
|
||||
</header>
|
||||
<DictModal v-model="showDictModal"/>
|
||||
@@ -110,10 +119,8 @@ watch(() => store.setting.showToolbar, n => {
|
||||
header {
|
||||
width: var(--toolbar-width);
|
||||
margin-top: 10rem;
|
||||
min-height: 60rem;
|
||||
background: var(--color-header-bg);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
border-radius: 8rem;
|
||||
margin-bottom: 30rem;
|
||||
//position: absolute;
|
||||
@@ -125,21 +132,37 @@ header {
|
||||
gap: 10rem;
|
||||
//opacity: 0;
|
||||
|
||||
.info {
|
||||
font-size: 16rem;
|
||||
color: var(--color-font-1);
|
||||
.content {
|
||||
min-height: 60rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
justify-content: space-between;
|
||||
|
||||
.info {
|
||||
font-size: 16rem;
|
||||
color: var(--color-font-1);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rem;
|
||||
}
|
||||
}
|
||||
|
||||
.options {
|
||||
.translate-progress {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rem;
|
||||
gap: $space;
|
||||
|
||||
.el-progress {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.arrow {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
|
||||
11
src/components/Toolbar/TrabslateSetting.vue
Normal file
11
src/components/Toolbar/TrabslateSetting.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
67
src/components/Toolbar/VolumeSetting.vue
Normal file
67
src/components/Toolbar/VolumeSetting.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import MiniModal from "@/components/MiniModal.vue";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import IconWrapper from "@/components/IconWrapper.vue";
|
||||
import Tooltip from "@/components/Tooltip.vue";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {useWindowClick} from "@/hooks/event.ts";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
|
||||
const store = useBaseStore()
|
||||
let show = $ref(false)
|
||||
|
||||
useWindowClick(() => show = false)
|
||||
|
||||
function toggle() {
|
||||
if (!show) emitter.emit(EventKey.closeOther)
|
||||
show = !show
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="setting" @click.stop="null">
|
||||
<Tooltip title="音效设置">
|
||||
<IconWrapper>
|
||||
<Icon icon="icon-park-outline:volume-notice"
|
||||
@click="toggle"
|
||||
/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<MiniModal v-model="show">
|
||||
<div class="mini-row">
|
||||
<label class="item-title">按键音</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="store.setting.keybroadVolume"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mini-row">
|
||||
<label class="item-title">按键音</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="store.setting.effectVolume"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</MiniModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/style";
|
||||
|
||||
.wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.setting {
|
||||
position: relative;
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -77,6 +77,6 @@ export default {
|
||||
padding: 10rem;
|
||||
color: var(--color-font-1);
|
||||
background: var(--color-tooltip-bg);
|
||||
//box-shadow: 1px 1px 6px #bbbbbb;
|
||||
box-shadow: 1px 1px 6px #bbbbbb;
|
||||
}
|
||||
</style>
|
||||
|
||||
12
src/hooks/event.ts
Normal file
12
src/hooks/event.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import {onMounted, onUnmounted} from "vue";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
|
||||
export function useWindowClick(cb: () => void) {
|
||||
onMounted(() => {
|
||||
emitter.on(EventKey.closeOther, cb)
|
||||
window.addEventListener('click', cb)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('click', cb)
|
||||
})
|
||||
}
|
||||
@@ -80,6 +80,14 @@ export const useBaseStore = defineStore('base', {
|
||||
setting: {
|
||||
showToolbar: true,
|
||||
show: false,
|
||||
|
||||
keyboardVolume: true,
|
||||
effectVolume: true,
|
||||
repeatCount: 1,
|
||||
repeatCustomCount: null,
|
||||
dictation: true,
|
||||
showTranslate: true,
|
||||
|
||||
value1: false,
|
||||
value2: 50,
|
||||
value3: 1,
|
||||
|
||||
@@ -183,6 +183,13 @@ export interface State {
|
||||
setting: {
|
||||
showToolbar: boolean,
|
||||
show: boolean,
|
||||
|
||||
keyboardVolume: boolean,
|
||||
effectVolume: boolean,
|
||||
repeatCount: number,
|
||||
repeatCustomCount?: number,
|
||||
dictation: boolean,
|
||||
|
||||
value1: boolean,
|
||||
value2: number,
|
||||
value3: number,
|
||||
|
||||
@@ -5,4 +5,5 @@ export const EventKey = {
|
||||
resetWord: 'resetWord',
|
||||
openSide: 'openSide',
|
||||
openStatModal: 'openStatModal',
|
||||
closeOther: 'closeOther',
|
||||
}
|
||||
Reference in New Issue
Block a user