update
This commit is contained in:
1
Note.md
1
Note.md
@@ -53,3 +53,4 @@ http://enpuz.com/ 语法分析工具
|
||||
|
||||
背单词页面div,位置应该恒定,不应该随翻译内容变动而跳动
|
||||
|
||||
点击句子播放的音乐,需要可暂停
|
||||
|
||||
6
components.d.ts
vendored
6
components.d.ts
vendored
@@ -40,12 +40,10 @@ declare module 'vue' {
|
||||
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']
|
||||
Index: typeof import('./src/components/Practice/PracticeArticle/Index.vue')['default']
|
||||
Input: typeof import('./src/components/Input.vue')['default']
|
||||
List: typeof import('./src/components/List.vue')['default']
|
||||
MiniModal: typeof import('./src/components/MiniModal.vue')['default']
|
||||
Modal: typeof import('./src/components/Modal/Modal.vue')['default']
|
||||
Panel: typeof import('./src/components/Practice/TypingArticle/Panel.vue')['default']
|
||||
PopConfirm: typeof import('./src/components/PopConfirm.vue')['default']
|
||||
Practice: typeof import('./src/components/Practice/Practice.vue')['default']
|
||||
PracticeArticle: typeof import('./src/components/Practice/PracticeArticle/PracticeArticle.vue')['default']
|
||||
@@ -57,10 +55,6 @@ declare module 'vue' {
|
||||
Toolbar: typeof import('./src/components/Toolbar/Toolbar.vue')['default']
|
||||
Tooltip: typeof import('./src/components/Tooltip.vue')['default']
|
||||
TranslateSetting: typeof import('./src/components/Toolbar/TranslateSetting.vue')['default']
|
||||
TypeArticle: typeof import('./src/components/Practice/TypingArticle/TypeArticle.vue')['default']
|
||||
TypeWord: typeof import('./src/components/Practice/PracticeWord/TypeWord.vue')['default']
|
||||
Typing: typeof import('./src/components/Practice/TypingArticle/Typing.vue')['default']
|
||||
TypingArti: typeof import('./src/components/Practice/TypingArticle/TypingArti.vue')['default']
|
||||
TypingArticle: typeof import('./src/components/Practice/PracticeArticle/TypingArticle.vue')['default']
|
||||
TypingWord: typeof import('./src/components/Practice/PracticeWord/TypingWord.vue')['default']
|
||||
VolumeIcon: typeof import('./src/components/VolumeIcon.vue')['default']
|
||||
|
||||
@@ -86,7 +86,7 @@ onUnmounted(() => {
|
||||
margin-bottom: 10rem;
|
||||
transition: all .3s;
|
||||
position: relative;
|
||||
margin-top: 30rem;
|
||||
margin-top: 20rem;
|
||||
|
||||
&.hide {
|
||||
margin-bottom: -90rem;
|
||||
|
||||
@@ -4,8 +4,6 @@ import Toolbar from "@/components/Toolbar/Toolbar.vue"
|
||||
import {onMounted, watch} from "vue";
|
||||
import {usePracticeStore} from "@/stores/practice.ts";
|
||||
import Footer from "@/components/Practice/Footer.vue";
|
||||
import TypeWord from "@/components/Practice/TypeWord.vue";
|
||||
import TypeArticle from "@/components/Practice/TypeArticle.vue";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {$ref} from "vue/macros";
|
||||
import Statistics from "@/components/Practice/Statistics.vue";
|
||||
@@ -17,14 +15,13 @@ import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {renewSectionTexts, renewSectionTranslates} from "@/hooks/translate.ts";
|
||||
import {MessageBox} from "@/utils/MessageBox.tsx";
|
||||
import EditSingleArticleModal from "@/components/Article/EditSingleArticleModal.vue";
|
||||
import PracticeArticle from "@/components/Practice/PracticeArticle/PracticeArticle.vue";
|
||||
|
||||
const practiceStore = usePracticeStore()
|
||||
const store = useBaseStore()
|
||||
const settingStore = useSettingStore()
|
||||
const runtimeStore = useRuntimeStore()
|
||||
|
||||
let showEditArticle = $ref(false)
|
||||
let editArticle = $ref<Article>(cloneDeep(DefaultArticle))
|
||||
|
||||
watch(practiceStore, () => {
|
||||
if (practiceStore.inputWordNumber < 1) {
|
||||
@@ -66,75 +63,9 @@ watch([
|
||||
|
||||
function getCurrentPractice() {
|
||||
// console.log('store.currentDict',store.currentDict)
|
||||
if (store.isArticle) {
|
||||
// return
|
||||
let currentArticle = store.currentDict.articles[store.currentDict.chapterIndex]
|
||||
let tempArticle = {...DefaultArticle, ...currentArticle}
|
||||
console.log('article', tempArticle)
|
||||
if (tempArticle.sections.length) {
|
||||
articleData.article = tempArticle
|
||||
} else {
|
||||
if (tempArticle.useTranslateType === TranslateType.none) {
|
||||
renewSectionTexts(tempArticle)
|
||||
articleData.article = tempArticle
|
||||
} else {
|
||||
if (tempArticle.useTranslateType === TranslateType.custom) {
|
||||
if (tempArticle.textCustomTranslate.trim()) {
|
||||
if (tempArticle.textCustomTranslateIsFormat) {
|
||||
renewSectionTexts(tempArticle)
|
||||
renewSectionTranslates(tempArticle, tempArticle.textCustomTranslate)
|
||||
articleData.article = tempArticle
|
||||
} else {
|
||||
//说明有本地翻译,但是没格式化成一行一行的
|
||||
MessageBox.confirm('检测到存在本地翻译,但未格式化,是否进行编辑?',
|
||||
'提示',
|
||||
() => {
|
||||
editArticle = tempArticle
|
||||
showEditArticle = true
|
||||
},
|
||||
() => {
|
||||
renewSectionTexts(tempArticle)
|
||||
tempArticle.useTranslateType = TranslateType.none
|
||||
store.currentDict.articles[store.currentDict.chapterIndex] = articleData.article = tempArticle
|
||||
},
|
||||
{
|
||||
confirmButtonText: '去编辑',
|
||||
cancelButtonText: '不需要翻译',
|
||||
})
|
||||
}
|
||||
} else {
|
||||
//没有本地翻译
|
||||
MessageBox.confirm(
|
||||
'没有本地翻译,是否进行编辑?',
|
||||
'提示',
|
||||
() => {
|
||||
editArticle = tempArticle
|
||||
showEditArticle = true
|
||||
},
|
||||
() => {
|
||||
renewSectionTexts(tempArticle)
|
||||
tempArticle.useTranslateType = TranslateType.none
|
||||
store.currentDict.articles[store.currentDict.chapterIndex] = articleData.article = tempArticle
|
||||
},
|
||||
{
|
||||
confirmButtonText: '去编辑',
|
||||
cancelButtonText: '不需要翻译',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (tempArticle.useTranslateType === TranslateType.network) {
|
||||
renewSectionTexts(tempArticle)
|
||||
renewSectionTranslates(tempArticle, tempArticle.textNetworkTranslate)
|
||||
store.currentDict.articles[store.currentDict.chapterIndex] = articleData.article = tempArticle
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wordData.words = cloneDeep(store.chapter)
|
||||
wordData.index = 0
|
||||
console.log('wordData', wordData)
|
||||
}
|
||||
wordData.words = cloneDeep(store.chapter)
|
||||
wordData.index = 0
|
||||
console.log('wordData', wordData)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@@ -161,18 +92,6 @@ function next() {
|
||||
// repeat()
|
||||
}
|
||||
|
||||
function saveArticle(val: Article) {
|
||||
console.log('saveArticle', val)
|
||||
showEditArticle = false
|
||||
// articleData.article = cloneDeep(store.currentDict.articles[store.currentDict.chapterIndex])
|
||||
store.currentDict.articles[store.currentDict.chapterIndex] = articleData.article = val
|
||||
}
|
||||
|
||||
function edit(val: Article) {
|
||||
editArticle = val
|
||||
showEditArticle = true
|
||||
}
|
||||
|
||||
function test() {
|
||||
MessageBox.confirm(
|
||||
'2您选择了“本地翻译”,但译文内容却为空白,是否修改为“不需要翻译”并保存?',
|
||||
@@ -189,21 +108,7 @@ function test() {
|
||||
<div class="practice">
|
||||
<Toolbar/>
|
||||
<!-- <BaseButton @click="test">test</BaseButton>-->
|
||||
<TypeArticle
|
||||
v-if="store.isArticle"
|
||||
:article="articleData.article"
|
||||
:sectionIndex="articleData.sectionIndex"
|
||||
:sentenceIndex="articleData.sentenceIndex"
|
||||
:wordIndex="articleData.wordIndex"
|
||||
:stringIndex="articleData.stringIndex"
|
||||
@next="next"
|
||||
@edit="edit"
|
||||
/>
|
||||
<TypeWord
|
||||
v-else
|
||||
:words="wordData.words"
|
||||
:index="wordData.index"
|
||||
/>
|
||||
<PracticeArticle v-if="store.isArticle"/>
|
||||
<Footer/>
|
||||
</div>
|
||||
<Statistics
|
||||
@@ -211,11 +116,6 @@ function test() {
|
||||
@repeat="repeat"
|
||||
@next="next"
|
||||
/>
|
||||
<EditSingleArticleModal
|
||||
v-model="showEditArticle"
|
||||
:article="editArticle"
|
||||
@save="saveArticle"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -224,7 +124,7 @@ function test() {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +1,197 @@
|
||||
<script setup lang="ts">
|
||||
import {$ref} from "vue/macros";
|
||||
import TypingArticle from "@/components/Practice/PracticeArticle/TypingArticle.vue";
|
||||
import TypingArticle from "./TypingArticle.vue";
|
||||
import {Article, DefaultArticle, TranslateType} from "@/types.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import TypingWord from "@/components/Practice/PracticeWord/TypingWord.vue";
|
||||
import ArticlePanel from "./ArticlePanel.vue";
|
||||
import {onMounted, watch} from "vue";
|
||||
import {renewSectionTexts, renewSectionTranslates} from "@/hooks/translate.ts";
|
||||
import {MessageBox} from "@/utils/MessageBox.tsx";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import EditSingleArticleModal from "@/components/Article/EditSingleArticleModal.vue";
|
||||
|
||||
const store = useBaseStore()
|
||||
let tabIndex = $ref(0)
|
||||
let wordData = $ref({
|
||||
words: [],
|
||||
index: -1
|
||||
})
|
||||
let index = $ref(0)
|
||||
let articleData = $ref({
|
||||
article: cloneDeep(DefaultArticle),
|
||||
sectionIndex: 0,
|
||||
sentenceIndex: 0,
|
||||
wordIndex: 0,
|
||||
stringIndex: 0,
|
||||
})
|
||||
let showEditArticle = $ref(false)
|
||||
let editArticle = $ref<Article>(cloneDeep(DefaultArticle))
|
||||
|
||||
watch([
|
||||
() => store.current.index,
|
||||
() => store.load,
|
||||
() => store.current.dictType,
|
||||
() => store.currentDict.chapterIndex,
|
||||
], n => {
|
||||
console.log('n', n)
|
||||
getCurrentPractice()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getCurrentPractice()
|
||||
})
|
||||
|
||||
function getCurrentPractice() {
|
||||
// console.log('store.currentDict',store.currentDict)
|
||||
// return
|
||||
if (!store.currentDict.articles.length) return
|
||||
let currentArticle = store.currentDict.articles[store.currentDict.chapterIndex]
|
||||
let tempArticle = {...DefaultArticle, ...currentArticle}
|
||||
console.log('article', tempArticle)
|
||||
if (tempArticle.sections.length) {
|
||||
articleData.article = tempArticle
|
||||
} else {
|
||||
if (tempArticle.useTranslateType === TranslateType.none) {
|
||||
renewSectionTexts(tempArticle)
|
||||
articleData.article = tempArticle
|
||||
} else {
|
||||
if (tempArticle.useTranslateType === TranslateType.custom) {
|
||||
if (tempArticle.textCustomTranslate.trim()) {
|
||||
if (tempArticle.textCustomTranslateIsFormat) {
|
||||
renewSectionTexts(tempArticle)
|
||||
renewSectionTranslates(tempArticle, tempArticle.textCustomTranslate)
|
||||
articleData.article = tempArticle
|
||||
} else {
|
||||
//说明有本地翻译,但是没格式化成一行一行的
|
||||
MessageBox.confirm('检测到存在本地翻译,但未格式化,是否进行编辑?',
|
||||
'提示',
|
||||
() => {
|
||||
editArticle = tempArticle
|
||||
showEditArticle = true
|
||||
},
|
||||
() => {
|
||||
renewSectionTexts(tempArticle)
|
||||
tempArticle.useTranslateType = TranslateType.none
|
||||
store.currentDict.articles[store.currentDict.chapterIndex] = articleData.article = tempArticle
|
||||
},
|
||||
{
|
||||
confirmButtonText: '去编辑',
|
||||
cancelButtonText: '不需要翻译',
|
||||
})
|
||||
}
|
||||
} else {
|
||||
//没有本地翻译
|
||||
MessageBox.confirm(
|
||||
'没有本地翻译,是否进行编辑?',
|
||||
'提示',
|
||||
() => {
|
||||
editArticle = tempArticle
|
||||
showEditArticle = true
|
||||
},
|
||||
() => {
|
||||
renewSectionTexts(tempArticle)
|
||||
tempArticle.useTranslateType = TranslateType.none
|
||||
store.currentDict.articles[store.currentDict.chapterIndex] = articleData.article = tempArticle
|
||||
},
|
||||
{
|
||||
confirmButtonText: '去编辑',
|
||||
cancelButtonText: '不需要翻译',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (tempArticle.useTranslateType === TranslateType.network) {
|
||||
renewSectionTexts(tempArticle)
|
||||
renewSectionTranslates(tempArticle, tempArticle.textNetworkTranslate)
|
||||
store.currentDict.articles[store.currentDict.chapterIndex] = articleData.article = tempArticle
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function saveArticle(val: Article) {
|
||||
console.log('saveArticle', val)
|
||||
showEditArticle = false
|
||||
// articleData.article = cloneDeep(store.currentDict.articles[store.currentDict.chapterIndex])
|
||||
store.currentDict.articles[store.currentDict.chapterIndex] = articleData.article = val
|
||||
}
|
||||
|
||||
function edit(val: Article) {
|
||||
editArticle = val
|
||||
showEditArticle = true
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="swiper-wrapper content">
|
||||
<div class="swiper-list" :class="`step${tabIndex}`">
|
||||
<div class="swiper-item">
|
||||
<TypingArticle/>
|
||||
</div>
|
||||
<div class="swiper-item">
|
||||
<TypingArticle/>
|
||||
<div class="practice-article">
|
||||
<div class="swiper-wrapper content">
|
||||
<div class="swiper-list" :class="`step${tabIndex}`">
|
||||
<div class="swiper-item">
|
||||
<TypingArticle
|
||||
:article="articleData.article"
|
||||
/>
|
||||
</div>
|
||||
<div class="swiper-item">
|
||||
<TypingWord
|
||||
:words="wordData.words"
|
||||
:index="wordData.index"
|
||||
v-if="tabIndex === 1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-wrapper">
|
||||
<ArticlePanel :list="[]" v-model:index="index"/>
|
||||
</div>
|
||||
|
||||
<EditSingleArticleModal
|
||||
v-model="showEditArticle"
|
||||
:article="editArticle"
|
||||
@save="saveArticle"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/style.scss";
|
||||
|
||||
$article-width: 50vw;
|
||||
|
||||
.swiper-wrapper {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
.swiper-list {
|
||||
transition: transform .3s;
|
||||
height: 200%;
|
||||
|
||||
.swiper-item {
|
||||
height: 50%;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.step1 {
|
||||
transform: translate3d(0, -50%, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.practice-article {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
width: $article-width;
|
||||
}
|
||||
|
||||
.panel-wrapper {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 10rem;
|
||||
z-index: 1;
|
||||
margin-left: calc(50% + ($article-width / 2) + $space);
|
||||
height: calc(100% - 20rem);
|
||||
}
|
||||
</style>
|
||||
@@ -1,10 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import {computed, nextTick, onMounted, watch, watchEffect} from "vue"
|
||||
import {computed, nextTick, onMounted, watch} from "vue"
|
||||
import {$computed, $ref} from "vue/macros";
|
||||
import {Article, ArticleWord, DefaultArticle, DisplayStatistics, ShortKeyMap, Word} from "@/types";
|
||||
import {useBaseStore} from "@/stores/base";
|
||||
import {usePracticeStore} from "@/stores/practice.ts";
|
||||
import TypeWord from "@/components/Practice/TypeWord.vue";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {usePlayBeep, usePlayCorrect, usePlayKeyboardAudio, usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
import {useOnKeyboardEventListener} from "@/hooks/event.ts";
|
||||
@@ -13,15 +12,13 @@ import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
import Tooltip from "@/components/Tooltip.vue";
|
||||
import IconWrapper from "@/components/IconWrapper.vue";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import WordPanel from "@/components/Practice/WordPanel.vue";
|
||||
import ArticlePanel from "@/components/Practice/ArticlePanel.vue";
|
||||
|
||||
interface IProps {
|
||||
article: Article,
|
||||
sectionIndex: number,
|
||||
sentenceIndex: number,
|
||||
wordIndex: number,
|
||||
stringIndex: number,
|
||||
sectionIndex?: number,
|
||||
sentenceIndex?: number,
|
||||
wordIndex?: number,
|
||||
stringIndex?: number,
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
@@ -428,49 +425,44 @@ function toggleCollect() {
|
||||
}
|
||||
}
|
||||
|
||||
let index = $ref(0)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="typing-wrapper">
|
||||
<div class="swiper-wrapper content">
|
||||
<div class="swiper-list" :class="`step${tabIndex}`">
|
||||
<div class="swiper-item">
|
||||
<div class="article-wrapper">
|
||||
<header>
|
||||
<div class="title">{{ props.article.title }}</div>
|
||||
<div class="titleTranslate" v-if="settingStore.translate">{{ props.article.titleTranslate }}</div>
|
||||
<div class="options">
|
||||
<Tooltip title="编辑(快捷键:Ctrl + E)">
|
||||
<IconWrapper>
|
||||
<Icon icon="tabler:edit" class="menu"
|
||||
@click="emit('edit',props.article)"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="忽略(快捷键:`)">
|
||||
<IconWrapper>
|
||||
<Icon icon="fluent:delete-20-regular" class="menu"
|
||||
@click="tabIndex = 1"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="收藏(快捷键:Enter)">
|
||||
<IconWrapper>
|
||||
<Icon :icon="`ph:star${collectIndex > -1?'-fill':''}`" class="menu"
|
||||
@click="toggleCollect"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="跳过(快捷键:Tab)">
|
||||
<IconWrapper>
|
||||
<Icon icon="icon-park-outline:go-ahead" class="menu"
|
||||
@click="emit('next')"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</header>
|
||||
<div class="article-content" ref="articleWrapperRef">
|
||||
<article>
|
||||
<div class="section"
|
||||
v-for="(section,indexI) in props.article.sections">
|
||||
<div class="typing-article">
|
||||
<header>
|
||||
<div class="title">{{ props.article.title }}</div>
|
||||
<div class="titleTranslate" v-if="settingStore.translate">{{ props.article.titleTranslate }}</div>
|
||||
<div class="options">
|
||||
<Tooltip title="编辑(快捷键:Ctrl + E)">
|
||||
<IconWrapper>
|
||||
<Icon icon="tabler:edit" class="menu"
|
||||
@click="emit('edit',props.article)"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="忽略(快捷键:`)">
|
||||
<IconWrapper>
|
||||
<Icon icon="fluent:delete-20-regular" class="menu"
|
||||
@click="tabIndex = 1"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="收藏(快捷键:Enter)">
|
||||
<IconWrapper>
|
||||
<Icon :icon="`ph:star${collectIndex > -1?'-fill':''}`" class="menu"
|
||||
@click="toggleCollect"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="跳过(快捷键:Tab)">
|
||||
<IconWrapper>
|
||||
<Icon icon="icon-park-outline:go-ahead" class="menu"
|
||||
@click="emit('next')"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</header>
|
||||
<div class="article-content" ref="articleWrapperRef">
|
||||
<article>
|
||||
<div class="section"
|
||||
v-for="(section,indexI) in props.article.sections">
|
||||
<span class="sentence"
|
||||
:class="[
|
||||
sectionIndex === indexI && sentenceIndex === indexJ && settingStore.dictation
|
||||
@@ -517,35 +509,19 @@ let index = $ref(0)
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</article>
|
||||
<div class="translate" v-show="settingStore.translate">
|
||||
<template v-for="(v,i) in props.article.sections">
|
||||
<div class="row"
|
||||
:class="`translate${i+'-'+j}`"
|
||||
v-for="(item,j) in v">
|
||||
<span class="space"></span>
|
||||
<Transition name="fade">
|
||||
<span class="text" v-if="item.translate">{{ item.translate }}</span>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<div class="translate" v-show="settingStore.translate">
|
||||
<template v-for="(v,i) in props.article.sections">
|
||||
<div class="row"
|
||||
:class="`translate${i+'-'+j}`"
|
||||
v-for="(item,j) in v">
|
||||
<span class="space"></span>
|
||||
<Transition name="fade">
|
||||
<span class="text" v-if="item.translate">{{ item.translate }}</span>
|
||||
</Transition>
|
||||
</div>
|
||||
<Teleport to="body">
|
||||
<div class="panel-wrapper">
|
||||
<ArticlePanel :list="[]" v-model:index="index"/>
|
||||
</div>
|
||||
</Teleport>
|
||||
</div>
|
||||
<div class="swiper-item">
|
||||
<TypeWord
|
||||
:words="wordData.words"
|
||||
:index="wordData.index"
|
||||
v-if="tabIndex === 1"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -560,105 +536,93 @@ let index = $ref(0)
|
||||
}
|
||||
|
||||
$article-width: 1000px;
|
||||
.typing-wrapper {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.typing-article {
|
||||
|
||||
.content {
|
||||
width: $article-width;
|
||||
}
|
||||
header {
|
||||
word-wrap: break-word;
|
||||
position: relative;
|
||||
padding: 15rem 0;
|
||||
|
||||
.article-wrapper {
|
||||
|
||||
header {
|
||||
word-wrap: break-word;
|
||||
position: relative;
|
||||
padding: 15rem 0;
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
color: rgba(gray, .8);
|
||||
font-size: 36rem;
|
||||
font-weight: 500;
|
||||
word-spacing: 3rem;
|
||||
//opacity: 0;
|
||||
}
|
||||
|
||||
.titleTranslate {
|
||||
@extend .title;
|
||||
font-size: 20rem;
|
||||
}
|
||||
|
||||
.options {
|
||||
position: absolute;
|
||||
right: 20rem;
|
||||
top: 0;
|
||||
display: flex;
|
||||
gap: 10rem;
|
||||
font-size: 18rem;
|
||||
}
|
||||
}
|
||||
|
||||
.article-content {
|
||||
position: relative;
|
||||
.title {
|
||||
text-align: center;
|
||||
color: rgba(gray, .8);
|
||||
font-size: 36rem;
|
||||
font-weight: 500;
|
||||
word-spacing: 3rem;
|
||||
//opacity: 0;
|
||||
}
|
||||
|
||||
article {
|
||||
//height: 100%;
|
||||
font-size: 24rem;
|
||||
line-height: 2.5;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
|
||||
color: gray;
|
||||
word-break: keep-all;
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
padding-top: 20rem;
|
||||
|
||||
.section {
|
||||
margin-bottom: $space;
|
||||
|
||||
.sentence {
|
||||
transition: all .3s;
|
||||
|
||||
&.dictation {
|
||||
letter-spacing: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.word {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.titleTranslate {
|
||||
@extend .title;
|
||||
font-size: 20rem;
|
||||
}
|
||||
|
||||
.translate {
|
||||
pointer-events: none;
|
||||
.options {
|
||||
position: absolute;
|
||||
right: 20rem;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
gap: 10rem;
|
||||
font-size: 18rem;
|
||||
color: gray;
|
||||
line-height: 3.5;
|
||||
letter-spacing: 3rem;
|
||||
//display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
.article-content {
|
||||
position: relative;
|
||||
//opacity: 0;
|
||||
}
|
||||
|
||||
.space {
|
||||
transition: all .3s;
|
||||
display: inline-block;
|
||||
article {
|
||||
//height: 100%;
|
||||
font-size: 24rem;
|
||||
line-height: 2.5;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
|
||||
color: gray;
|
||||
word-break: keep-all;
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
padding-top: 20rem;
|
||||
|
||||
.section {
|
||||
margin-bottom: $space;
|
||||
|
||||
.sentence {
|
||||
transition: all .3s;
|
||||
|
||||
&.dictation {
|
||||
letter-spacing: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.word {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.translate {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-size: 18rem;
|
||||
color: gray;
|
||||
line-height: 3.5;
|
||||
letter-spacing: 3rem;
|
||||
//display: none;
|
||||
|
||||
.row {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
|
||||
.space {
|
||||
transition: all .3s;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -713,27 +677,6 @@ $article-width: 1000px;
|
||||
}
|
||||
}
|
||||
|
||||
.swiper-wrapper {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
.swiper-list {
|
||||
transition: transform .3s;
|
||||
height: 200%;
|
||||
|
||||
.swiper-item {
|
||||
height: 50%;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.step1 {
|
||||
transform: translate3d(0, -50%, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes underline {
|
||||
0%, 100% {
|
||||
border-left: 1.3rem solid black;
|
||||
@@ -743,12 +686,4 @@ $article-width: 1000px;
|
||||
}
|
||||
}
|
||||
|
||||
.panel-wrapper {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 10rem;
|
||||
z-index: 1;
|
||||
margin-left: calc(50% + ($article-width / 2) + $space);
|
||||
height: calc(100% - 20rem);
|
||||
}
|
||||
</style>
|
||||
@@ -2,8 +2,7 @@
|
||||
import {onMounted, watch} from "vue"
|
||||
import {$computed, $ref} from "vue/macros"
|
||||
import {useBaseStore} from "@/stores/base.ts"
|
||||
import {DictType, DisplayStatistics, ShortKeyMap, Word} from "../../types";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {DictType, DisplayStatistics, ShortKeyMap, Word} from "../../../types";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts"
|
||||
import {cloneDeep} from "lodash-es"
|
||||
import {usePracticeStore} from "@/stores/practice.ts"
|
||||
@@ -13,7 +12,7 @@ import {useOnKeyboardEventListener} from "@/hooks/event.ts";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import VolumeIcon from "@/components/VolumeIcon.vue";
|
||||
import Tooltip from "@/components/Tooltip.vue";
|
||||
import WordPanel from "@/components/Practice/WordPanel.vue";
|
||||
import WordPanel from "./WordPanel.vue";
|
||||
import IconWrapper from "@/components/IconWrapper.vue";
|
||||
|
||||
interface IProps {
|
||||
|
||||
@@ -63,9 +63,9 @@ export const useBaseStore = defineStore('base', {
|
||||
}
|
||||
],
|
||||
current: {
|
||||
// dictType: DictType.word,
|
||||
dictType: DictType.article,
|
||||
index: 0,
|
||||
dictType: DictType.word,
|
||||
// dictType: DictType.article,
|
||||
index: 1,
|
||||
editIndex: 0,
|
||||
repeatNumber: 0,
|
||||
},
|
||||
@@ -192,9 +192,12 @@ export const useBaseStore = defineStore('base', {
|
||||
DictType.article,
|
||||
DictType.customArticle,
|
||||
].includes(this.current.dictType)) {
|
||||
console.log(1,this.currentDict)
|
||||
if (!this.currentDict.articles.length) {
|
||||
console.log(2)
|
||||
let r = await fetch(`./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`)
|
||||
r.json().then((v: any[]) => {
|
||||
console.log(3)
|
||||
this.currentDict.articles = cloneDeep(v.map(v => {
|
||||
v.id = uuidv4()
|
||||
return v
|
||||
|
||||
Reference in New Issue
Block a user