update dict
This commit is contained in:
@@ -36,8 +36,7 @@
|
||||
--panel-width: 400rem;
|
||||
--space: 20rem;
|
||||
--radius: 8rem;
|
||||
--shadow: rgba(17, 17, 26, 0.05) 0px 4px 16px, rgba(17, 17, 26, 0.05) 0px 8px 32px;
|
||||
--shadow: rgba(0, 0, 0, 0.08) 0px 4px 12px;;
|
||||
--shadow: rgba(0, 0, 0, 0.08) 0px 4px 12px;
|
||||
--panel-margin-left: calc(50% - var(--practice-wrapper-translateX) / 2 + var(--toolbar-width) / 2 + 24rem);
|
||||
--article-panel-margin-left: calc(50% - var(--practice-wrapper-translateX) / 2 + var(--article-width) / 2 + 24rem);
|
||||
--anim-time: 0.5s;
|
||||
|
||||
2405
src/assets/dictionary2.ts
Normal file
2405
src/assets/dictionary2.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
import {onMounted, onUnmounted, watch} from "vue"
|
||||
import {$computed, $ref} from "vue/macros"
|
||||
import {useBaseStore} from "@/stores/base.ts"
|
||||
import {DefaultDisplayStatistics, DictType, ShortcutKey, Sort, Word} from "../../../../types.ts";
|
||||
import {DefaultDisplayStatistics, DictType, ShortcutKey, Sort, Word} from "@/types.ts";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts"
|
||||
import {cloneDeep, reverse, shuffle} from "lodash-es"
|
||||
import {usePracticeStore} from "@/stores/practice.ts"
|
||||
|
||||
280
src/pages/pc/practice/practice-word/Typing.vue
Normal file
280
src/pages/pc/practice/practice-word/Typing.vue
Normal file
@@ -0,0 +1,280 @@
|
||||
<script setup lang="ts">
|
||||
import {DefaultWord, ShortcutKey, Word} from "@/types.ts";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {$computed, $ref} from "vue/macros";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {usePracticeStore} from "@/stores/practice.ts";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {usePlayBeep, usePlayCorrect, usePlayKeyboardAudio, usePlayWordAudio, useTTsPlayAudio} from "@/hooks/sound.ts";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {onUnmounted, watch, onMounted} from "vue";
|
||||
import Tooltip from "@/components/Tooltip.vue";
|
||||
|
||||
interface IProps {
|
||||
word: Word,
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
word: () => cloneDeep(DefaultWord),
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
complete: [],
|
||||
wrong: []
|
||||
}>()
|
||||
|
||||
let input = $ref('')
|
||||
let wrong = $ref('')
|
||||
let showFullWord = $ref(false)
|
||||
//输入锁定,因为跳转到下一个单词有延时,如果重复在延时期间内重复输入,导致会跳转N次
|
||||
let inputLock = false
|
||||
let wordRepeatCount = 0
|
||||
const settingStore = useSettingStore()
|
||||
|
||||
const playBeep = usePlayBeep()
|
||||
const playCorrect = usePlayCorrect()
|
||||
const playKeyboardAudio = usePlayKeyboardAudio()
|
||||
const playWordAudio = usePlayWordAudio()
|
||||
const ttsPlayAudio = useTTsPlayAudio()
|
||||
const volumeIconRef: any = $ref()
|
||||
const volumeTranslateIconRef: any = $ref()
|
||||
|
||||
let displayWord = $computed(() => {
|
||||
return props.word.name.slice(input.length + wrong.length)
|
||||
})
|
||||
|
||||
watch(() => props.word, () => {
|
||||
wrong = input = ''
|
||||
wordRepeatCount = 0
|
||||
inputLock = false
|
||||
if (settingStore.wordSound) {
|
||||
volumeIconRef?.play(400, true)
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
emitter.on(EventKey.resetWord, () => {
|
||||
wrong = input = ''
|
||||
})
|
||||
|
||||
emitter.on(EventKey.onTyping, onTyping)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.off(EventKey.resetWord)
|
||||
emitter.off(EventKey.onTyping, onTyping)
|
||||
})
|
||||
|
||||
function repeat() {
|
||||
setTimeout(() => {
|
||||
wrong = input = ''
|
||||
wordRepeatCount++
|
||||
inputLock = false
|
||||
|
||||
if (settingStore.wordSound) {
|
||||
volumeIconRef?.play()
|
||||
}
|
||||
}, settingStore.waitTimeForChangeWord)
|
||||
}
|
||||
|
||||
async function onTyping(e: KeyboardEvent) {
|
||||
if (inputLock) return
|
||||
inputLock = true
|
||||
let letter = e.key
|
||||
let isTypingRight = false
|
||||
let isWordRight = false
|
||||
if (settingStore.ignoreCase) {
|
||||
isTypingRight = letter.toLowerCase() === props.word.name[input.length].toLowerCase()
|
||||
isWordRight = (input + letter).toLowerCase() === props.word.name.toLowerCase()
|
||||
} else {
|
||||
isTypingRight = letter === props.word.name[input.length]
|
||||
isWordRight = (input + letter) === props.word.name
|
||||
}
|
||||
if (isTypingRight) {
|
||||
input += letter
|
||||
wrong = ''
|
||||
playKeyboardAudio()
|
||||
} else {
|
||||
emit('wrong')
|
||||
wrong = letter
|
||||
playKeyboardAudio()
|
||||
playBeep()
|
||||
volumeIconRef?.play()
|
||||
setTimeout(() => {
|
||||
wrong = ''
|
||||
}, 500)
|
||||
}
|
||||
|
||||
if (isWordRight) {
|
||||
playCorrect()
|
||||
if (settingStore.repeatCount == 100) {
|
||||
if (settingStore.repeatCustomCount <= wordRepeatCount + 1) {
|
||||
setTimeout(() => emit('complete'), settingStore.waitTimeForChangeWord)
|
||||
} else {
|
||||
repeat()
|
||||
}
|
||||
} else {
|
||||
if (settingStore.repeatCount <= wordRepeatCount + 1) {
|
||||
setTimeout(() => emit('complete'), settingStore.waitTimeForChangeWord)
|
||||
} else {
|
||||
repeat()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
inputLock = false
|
||||
}
|
||||
}
|
||||
|
||||
function del() {
|
||||
playKeyboardAudio()
|
||||
|
||||
if (wrong) {
|
||||
wrong = ''
|
||||
} else {
|
||||
input = input.slice(0, -1)
|
||||
}
|
||||
}
|
||||
|
||||
function showWord() {
|
||||
if (settingStore.allowWordTip) {
|
||||
showFullWord = true
|
||||
}
|
||||
}
|
||||
|
||||
function hideWord() {
|
||||
showFullWord = false
|
||||
}
|
||||
|
||||
function play() {
|
||||
volumeIconRef?.play()
|
||||
}
|
||||
|
||||
defineExpose({del, showWord, hideWord, play})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="typing-word">
|
||||
<div class="translate"
|
||||
:style="{
|
||||
fontSize: settingStore.fontSize.wordTranslateFontSize +'rem',
|
||||
opacity: settingStore.translate ? 1 : 0
|
||||
}"
|
||||
>
|
||||
<div class="translate-item" v-for="(v,i) in word.trans">
|
||||
<span>{{ v }}</span>
|
||||
<!-- <div class="volumeIcon">-->
|
||||
<!-- <Tooltip-->
|
||||
<!-- v-if="i === word.trans.length - 1"-->
|
||||
<!-- :title="`发音(快捷键:${settingStore.shortcutKeyMap[ShortcutKey.PlayTranslatePronunciation]})`"-->
|
||||
<!-- >-->
|
||||
<!-- <VolumeIcon-->
|
||||
<!-- ref="volumeTranslateIconRef"-->
|
||||
<!-- :simple="true"-->
|
||||
<!-- :cb="()=>ttsPlayAudio(word.trans.join(';'))"/>-->
|
||||
<!-- </Tooltip>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
<div class="word-wrapper">
|
||||
<div class="word"
|
||||
:class="wrong && 'is-wrong'"
|
||||
:style="{fontSize: settingStore.fontSize.wordForeignFontSize +'rem'}"
|
||||
>
|
||||
<span class="input" v-if="input">{{ input }}</span>
|
||||
<span class="wrong" v-if="wrong">{{ wrong }}</span>
|
||||
<template v-if="settingStore.dictation">
|
||||
<span class="letter" v-if="!showFullWord"
|
||||
@mouseenter="settingStore.allowWordTip && (showFullWord = true)">{{
|
||||
displayWord.split('').map(() => '_').join('')
|
||||
}}</span>
|
||||
<span class="letter" v-else @mouseleave="showFullWord = false">{{ displayWord }}</span>
|
||||
</template>
|
||||
<span class="letter" v-else>{{ displayWord }}</span>
|
||||
</div>
|
||||
<Tooltip
|
||||
:title="`发音(快捷键:${settingStore.shortcutKeyMap[ShortcutKey.PlayWordPronunciation]})`"
|
||||
>
|
||||
<VolumeIcon ref="volumeIconRef" :simple="true" :cb="() => playWordAudio(word.name)"/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div class="phonetic" v-if="settingStore.wordSoundType === 'us' && word.usphone">[{{ word.usphone}}]</div>
|
||||
<div class="phonetic" v-if="settingStore.wordSoundType === 'uk' && word.ukphone">[{{ word.ukphone }}]</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/variable";
|
||||
|
||||
.typing-word {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
word-break: break-word;
|
||||
position: relative;
|
||||
|
||||
.phonetic, .translate {
|
||||
font-size: 20rem;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
.phonetic {
|
||||
margin-top: 5rem;
|
||||
font-family: var(--word-font-family);
|
||||
}
|
||||
|
||||
.translate {
|
||||
position: absolute;
|
||||
transform: translateY(-50%);
|
||||
margin-bottom: 90rem;
|
||||
color: var(--color-font-2);
|
||||
|
||||
&:hover {
|
||||
.volumeIcon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.translate-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rem;
|
||||
}
|
||||
|
||||
.volumeIcon {
|
||||
transition: opacity .3s;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.word-wrapper {
|
||||
margin-left: 30rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rem;
|
||||
color: var(--color-font-1);
|
||||
|
||||
.word {
|
||||
font-size: 48rem;
|
||||
line-height: 1;
|
||||
font-family: var(--word-font-family);
|
||||
letter-spacing: 5rem;
|
||||
|
||||
.input {
|
||||
color: rgb(22, 163, 74);
|
||||
}
|
||||
|
||||
.wrong {
|
||||
color: rgba(red, 0.6);
|
||||
}
|
||||
|
||||
&.is-wrong {
|
||||
animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user