wip
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@
|
||||
--article-width: 50vw;
|
||||
--article-toolbar-width: 50vw;
|
||||
--article-panel-width: 20rem;
|
||||
--article-panel-margin-left: calc(50% + var(--article-width) / 2 + 1rem);
|
||||
--article-panel-margin-left: calc(50vw + var(--article-width) / 2 + var(--aside-width) / 2 + 1rem);
|
||||
|
||||
--toolbar-width: 50rem;
|
||||
--panel-width: 24rem;
|
||||
@@ -26,7 +26,7 @@
|
||||
--modal-padding: 1.3rem;
|
||||
--space: 0.9rem;
|
||||
--stat-gap: 1rem;
|
||||
--word-panel-margin-left: calc(50% + var(--toolbar-width) / 2 + 1rem);
|
||||
--word-panel-margin-left: calc(50vw + var(--aside-width) / 2 + var(--toolbar-width) / 2 + 1rem);
|
||||
--anim-time: 0.5s;
|
||||
|
||||
--color-input-color: black;
|
||||
@@ -374,13 +374,8 @@ a {
|
||||
@apply flex-col;
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply rounded-xl p-4 mb-8 shadow-lg box-border relative;
|
||||
background: var(--color-second);
|
||||
}
|
||||
|
||||
.card-white {
|
||||
@extend .card;
|
||||
@apply card;
|
||||
background: var(--color-card-bg);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import { useSettingStore } from '@/stores/setting.ts'
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
defineProps<{
|
||||
@@ -8,12 +8,16 @@ defineProps<{
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex justify-center relative h-screen"
|
||||
:class="!settingStore.showToolbar && 'footer-hide'">
|
||||
<div class="flex justify-center relative" :class="!settingStore.showToolbar && 'footer-hide'">
|
||||
<div class="wrap">
|
||||
<slot name="practice"></slot>
|
||||
</div>
|
||||
<div class="panel-wrap" :style="{left:panelLeft}" :class="{'has-panel': settingStore.showPanel}" @click.self="settingStore.showPanel = false">
|
||||
<div
|
||||
class="panel-wrap"
|
||||
:style="{ left: panelLeft }"
|
||||
:class="{ 'has-panel': settingStore.showPanel }"
|
||||
@click.self="settingStore.showPanel = false"
|
||||
>
|
||||
<slot name="panel"></slot>
|
||||
</div>
|
||||
<div class="footer-wrap">
|
||||
@@ -23,17 +27,11 @@ defineProps<{
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
.wrap {
|
||||
transition: all var(--anim-time);
|
||||
height: calc(100vh - 8rem);
|
||||
}
|
||||
|
||||
.footer-hide {
|
||||
.wrap {
|
||||
height: calc(100vh - 3rem) !important;
|
||||
}
|
||||
|
||||
.footer-wrap {
|
||||
bottom: -6rem;
|
||||
}
|
||||
@@ -41,14 +39,14 @@ defineProps<{
|
||||
|
||||
.footer-wrap {
|
||||
position: fixed;
|
||||
bottom: calc(0.8rem + env(safe-area-inset-bottom, 0px));
|
||||
bottom: calc(env(safe-area-inset-bottom, 0px));
|
||||
transition: all var(--anim-time);
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.panel-wrap {
|
||||
position: absolute;
|
||||
top: .8rem;
|
||||
position: fixed;
|
||||
top: 0.8rem;
|
||||
z-index: 1;
|
||||
height: calc(100vh - 1.8rem);
|
||||
}
|
||||
@@ -61,24 +59,24 @@ defineProps<{
|
||||
padding: 0 1rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
.footer-hide {
|
||||
.wrap {
|
||||
height: calc(100vh - 2rem) !important;
|
||||
}
|
||||
|
||||
|
||||
.footer-wrap {
|
||||
bottom: calc(-10rem + env(safe-area-inset-bottom, 0px));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.footer-wrap {
|
||||
bottom: calc(0.5rem + env(safe-area-inset-bottom, 0px));
|
||||
left: 0.5rem;
|
||||
right: 0.5rem;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
|
||||
.panel-wrap {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
@@ -92,10 +90,10 @@ defineProps<{
|
||||
justify-content: center;
|
||||
padding: 1rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
|
||||
// 当面板未显示时,禁用指针事件
|
||||
pointer-events: none;
|
||||
|
||||
|
||||
// 只有当面板显示时才添加背景蒙版并启用指针事件
|
||||
&.has-panel {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
@@ -110,19 +108,19 @@ defineProps<{
|
||||
height: calc(100vh - 5rem);
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
.footer-hide {
|
||||
.wrap {
|
||||
height: calc(100vh - 1.5rem) !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.footer-wrap {
|
||||
bottom: calc(0.3rem + env(safe-area-inset-bottom, 0px));
|
||||
left: 0.3rem;
|
||||
right: 0.3rem;
|
||||
}
|
||||
|
||||
|
||||
.panel-wrap {
|
||||
padding: 0.5rem;
|
||||
left: 0 !important;
|
||||
|
||||
@@ -4,7 +4,7 @@ import BackIcon from '@/components/BackIcon.vue'
|
||||
import Empty from '@/components/Empty.vue'
|
||||
import ArticleList from '@/components/list/ArticleList.vue'
|
||||
import { useBaseStore } from '@/stores/base.ts'
|
||||
import { Article, Dict, DictId, DictType } from '@/types/types.ts'
|
||||
import { Article, Dict, DictId, DictType, ShortcutKey } from '@/types/types.ts'
|
||||
import { useRuntimeStore } from '@/stores/runtime.ts'
|
||||
import BaseButton from '@/components/BaseButton.vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
@@ -19,6 +19,7 @@ import { useSettingStore } from '@/stores/setting.ts'
|
||||
import { useFetch } from '@vueuse/core'
|
||||
import { AppEnv, DICT_LIST } from '@/config/env.ts'
|
||||
import { detail } from '@/apis'
|
||||
import BaseIcon from '@/components/BaseIcon.vue'
|
||||
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const settingStore = useSettingStore()
|
||||
@@ -101,6 +102,7 @@ async function init() {
|
||||
}
|
||||
}
|
||||
}
|
||||
selectArticle = runtimeStore.editDict.articles[0]
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
@@ -174,11 +176,17 @@ const list = $computed(() => {
|
||||
}),
|
||||
].concat(runtimeStore.editDict.articles)
|
||||
})
|
||||
|
||||
let showAudio = $ref(false)
|
||||
let showTranslate = $ref(true)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-second h-screen overflow-hidden">
|
||||
<div class="mb-0 flex h-full p-space box-border flex-col" v-if="showBookDetail">
|
||||
<div class="center h-screen overflow-hidden">
|
||||
<div
|
||||
class="mb-0 flex p-space box-border flex-col bg-second w-full 3xl:w-7/10 2xl:w-8/10 xl:w-full 2xl:card 2xl:h-[97vh] h-full"
|
||||
v-if="showBookDetail"
|
||||
>
|
||||
<div class="dict-header flex justify-between items-center relative">
|
||||
<BackIcon class="dict-back z-2" />
|
||||
<div class="dict-title absolute text-2xl text-align-center w-full">{{ runtimeStore.editDict.name }}</div>
|
||||
@@ -191,9 +199,8 @@ const list = $computed(() => {
|
||||
<BaseButton :loading="studyLoading || loading" @click="addMyStudyList">学习</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-1 overflow-hidden mt-3">
|
||||
<div class="w-70 overflow-auto">
|
||||
<div class="3xl:w-80 2xl:w-60 xl:w-55 lg:w-50 overflow-auto">
|
||||
<ArticleList
|
||||
:show-desc="true"
|
||||
v-if="runtimeStore.editDict.length"
|
||||
@@ -217,11 +224,49 @@ const list = $computed(() => {
|
||||
<div class="text-lg">介绍:{{ runtimeStore.editDict.description }}</div>
|
||||
</div>
|
||||
<div class="text-base" v-if="totalSpend">总学习时长:{{ totalSpend }}</div>
|
||||
|
||||
<div class="line my-3"></div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="">
|
||||
<div class="text-3xl flex justify-between items-center relative">
|
||||
<span>
|
||||
<span class="font-bold">{{ selectArticle.title }}</span>
|
||||
<span class="ml-6 text-2xl" v-if="showTranslate">{{ selectArticle.titleTranslate }}</span>
|
||||
</span>
|
||||
<div>
|
||||
<BaseIcon title="显示音频" @click="showAudio = !showAudio">
|
||||
<IconBxVolumeFull />
|
||||
</BaseIcon>
|
||||
<BaseIcon :title="`开关释义显示`" @click="showTranslate = !showTranslate">
|
||||
<IconFluentTranslate16Regular v-if="showTranslate" />
|
||||
<IconFluentTranslateOff16Regular v-else />
|
||||
</BaseIcon>
|
||||
</div>
|
||||
</div>
|
||||
<ArticleAudio
|
||||
v-if="showAudio"
|
||||
class="mt-4"
|
||||
:article="selectArticle"
|
||||
:autoplay="settingStore.articleAutoPlayNext"
|
||||
@ended="next"
|
||||
/>
|
||||
<div class="mb-4 mt-4 text-2xl" v-if="selectArticle?.question?.text">
|
||||
Question: {{ selectArticle?.question?.text }}
|
||||
</div>
|
||||
<div class="text-2xl line-height-normal en-article-family" v-if="selectArticle.text">
|
||||
<div class="my-6" v-for="t in selectArticle.text.split('\n\n')">{{ t }}</div>
|
||||
<div class="text-right italic mb-5">{{ selectArticle?.quote?.text }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line my-10"></div>
|
||||
<div class="mt-6" v-if="showTranslate">
|
||||
<div class="text-xl line-height-normal" v-if="selectArticle.textTranslate">
|
||||
<div class="my-5" v-for="t in selectArticle.textTranslate.split('\n\n')">{{ t }}</div>
|
||||
<div class="text-right italic mb-5">{{ selectArticle?.quote?.translate }}</div>
|
||||
</div>
|
||||
<Empty v-else />
|
||||
</div>
|
||||
<div class="font-family text-base mb-4 pr-2" v-if="currentPractice.length">
|
||||
<div class="line my-10"></div>
|
||||
<div class="text-2xl font-bold">学习记录</div>
|
||||
<div class="mt-1 mb-3">总学习时长:{{ msToHourMinute(total(currentPractice, 'spend')) }}</div>
|
||||
<div
|
||||
@@ -232,35 +277,6 @@ const list = $computed(() => {
|
||||
<span>{{ msToHourMinute(i.spend) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="en-article-family">
|
||||
<div class="text-3xl">
|
||||
<span class="">{{ selectArticle.title }}</span>
|
||||
<span class="ml-6 text-2xl">{{ selectArticle.titleTranslate }}</span>
|
||||
</div>
|
||||
<div class="mb-10 mt-6 text-2xl" v-if="selectArticle?.question?.text">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="">First Listen and then answer the following question.</span>
|
||||
<ArticleAudio
|
||||
class="w-100!"
|
||||
:article="selectArticle"
|
||||
:autoplay="settingStore.articleAutoPlayNext"
|
||||
@ended="next"
|
||||
/>
|
||||
</div>
|
||||
<div class="decoration-dashed underline">{{ selectArticle?.question?.text }}</div>
|
||||
</div>
|
||||
<div class="text-2xl line-height-normal" v-if="selectArticle.text">
|
||||
<div class="my-5" v-for="t in selectArticle.text.split('\n\n')">{{ t }}</div>
|
||||
<div class="text-right italic mb-5">{{ selectArticle?.quote?.text }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-13">
|
||||
<div class="text-xl line-height-normal" v-if="selectArticle.textTranslate">
|
||||
<div class="my-5" v-for="t in selectArticle.textTranslate.split('\n\n')">{{ t }}</div>
|
||||
<div class="text-right italic mb-5">{{ selectArticle?.quote?.translate }}</div>
|
||||
</div>
|
||||
<Empty v-else />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<Empty v-else />
|
||||
|
||||
@@ -11,11 +11,7 @@ import SettingDialog from '@/components/setting/SettingDialog.vue'
|
||||
import { AppEnv, DICT_LIST, LIB_JS_URL, TourConfig } from '@/config/env.ts'
|
||||
import { genArticleSectionData, usePlaySentenceAudio } from '@/hooks/article.ts'
|
||||
import { useArticleOptions } from '@/hooks/dict.ts'
|
||||
import {
|
||||
useDisableEventListener,
|
||||
useOnKeyboardEventListener,
|
||||
useStartKeyboardEventListener,
|
||||
} from '@/hooks/event.ts'
|
||||
import { useDisableEventListener, useOnKeyboardEventListener, useStartKeyboardEventListener } from '@/hooks/event.ts'
|
||||
import useTheme from '@/hooks/theme.ts'
|
||||
import ArticleAudio from '@/pages/article/components/ArticleAudio.vue'
|
||||
import EditSingleArticleModal from '@/pages/article/components/EditSingleArticleModal.vue'
|
||||
@@ -36,16 +32,7 @@ import {
|
||||
Statistics,
|
||||
Word,
|
||||
} from '@/types/types.ts'
|
||||
import {
|
||||
_getDictDataByUrl,
|
||||
_nextTick,
|
||||
cloneDeep,
|
||||
isMobile,
|
||||
loadJsLib,
|
||||
msToMinute,
|
||||
resourceWrap,
|
||||
total,
|
||||
} from '@/utils'
|
||||
import { _getDictDataByUrl, _nextTick, cloneDeep, isMobile, loadJsLib, msToMinute, resourceWrap, total } from '@/utils'
|
||||
import { getPracticeArticleCache, setPracticeArticleCache } from '@/utils/cache.ts'
|
||||
import { emitter, EventKey, useEvents } from '@/utils/eventBus.ts'
|
||||
import { computed, onMounted, onUnmounted, provide, watch } from 'vue'
|
||||
@@ -382,10 +369,7 @@ function wrong(word: Word) {
|
||||
}
|
||||
|
||||
function nextWord(word: ArticleWord) {
|
||||
if (
|
||||
!store.allIgnoreWords.includes(word.word.toLowerCase()) &&
|
||||
word.type === PracticeArticleWordType.Word
|
||||
) {
|
||||
if (!store.allIgnoreWords.includes(word.word.toLowerCase()) && word.type === PracticeArticleWordType.Word) {
|
||||
statStore.inputWordNumber++
|
||||
}
|
||||
}
|
||||
@@ -506,10 +490,7 @@ provide('currentPractice', currentPractice)
|
||||
<template v-slot:panel>
|
||||
<Panel :style="{ width: 'var(--article-panel-width)' }">
|
||||
<template v-slot:title>
|
||||
<span
|
||||
>{{ store.sbook.name }} ({{ store.sbook.lastLearnIndex + 1 }} /
|
||||
{{ articleData.list.length }})</span
|
||||
>
|
||||
<span>{{ store.sbook.name }} ({{ store.sbook.lastLearnIndex + 1 }} / {{ articleData.list.length }})</span>
|
||||
</template>
|
||||
<div class="panel-page-item pl-4">
|
||||
<ArticleList
|
||||
@@ -525,28 +506,28 @@ provide('currentPractice', currentPractice)
|
||||
</Panel>
|
||||
</template>
|
||||
<template v-slot:footer>
|
||||
<div class="footer">
|
||||
<Tooltip :title="settingStore.showToolbar ? '收起' : '展开'">
|
||||
<IconFluentChevronLeft20Filled
|
||||
@click="settingStore.showToolbar = !settingStore.showToolbar"
|
||||
class="arrow"
|
||||
:class="!settingStore.showToolbar && 'down'"
|
||||
color="#999"
|
||||
/>
|
||||
</Tooltip>
|
||||
<div class="bottom">
|
||||
<div class="footer pb-3">
|
||||
<div class="center h-10">
|
||||
<Tooltip :title="settingStore.showToolbar ? '收起' : '展开'">
|
||||
<IconFluentChevronLeft20Filled
|
||||
@click="settingStore.showToolbar = !settingStore.showToolbar"
|
||||
:class="!settingStore.showToolbar && 'down'"
|
||||
color="#999"
|
||||
class="arrow"
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div class="bottom ">
|
||||
<div class="flex justify-between items-center gap-2">
|
||||
<div class="stat">
|
||||
<div class="row">
|
||||
<div class="num">
|
||||
{{ currentPractice.length }}次/{{ msToMinute(total(currentPractice, 'spend')) }}
|
||||
</div>
|
||||
<div class="num">{{ currentPractice.length }}次/{{ msToMinute(total(currentPractice, 'spend')) }}</div>
|
||||
<div class="line"></div>
|
||||
<div class="name">记录</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<!-- <div class="num">{{statStore.spend }}分钟</div>-->
|
||||
<div class="num">{{ Math.floor(statStore.spend / 1000 / 60) }}分钟</div>
|
||||
<!-- <div class="num">{{statStore.spend }}分钟</div>-->
|
||||
<div class="num">{{ Math.floor(statStore.spend / 1000 / 60) }}分钟</div>
|
||||
<div class="line"></div>
|
||||
<div class="name">时间</div>
|
||||
</div>
|
||||
@@ -557,9 +538,7 @@ provide('currentPractice', currentPractice)
|
||||
<IconFluentQuestionCircle20Regular width="18" />
|
||||
<template #reference>
|
||||
<div>
|
||||
统计词数{{
|
||||
settingStore.ignoreSimpleWord ? '不包含' : '包含'
|
||||
}}简单词,不包含已掌握
|
||||
统计词数{{ settingStore.ignoreSimpleWord ? '不包含' : '包含' }}简单词,不包含已掌握
|
||||
<div>简单词可在设置 -> 练习设置 -> 简单词过滤中修改</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -581,10 +560,7 @@ provide('currentPractice', currentPractice)
|
||||
<div class="flex gap-2 center">
|
||||
<SettingDialog type="article" />
|
||||
|
||||
<BaseIcon
|
||||
:title="`下一句(${settingStore.shortcutKeyMap[ShortcutKey.Next]})`"
|
||||
@click="skip"
|
||||
>
|
||||
<BaseIcon :title="`下一句(${settingStore.shortcutKeyMap[ShortcutKey.Next]})`" @click="skip">
|
||||
<IconFluentArrowBounce20Regular class="transform-rotate-180" />
|
||||
</BaseIcon>
|
||||
<BaseIcon
|
||||
@@ -636,6 +612,7 @@ provide('currentPractice', currentPractice)
|
||||
<style scoped lang="scss">
|
||||
.footer {
|
||||
width: var(--article-toolbar-width);
|
||||
@apply bg-primary;
|
||||
|
||||
.bottom {
|
||||
@apply relative w-full box-border rounded-lg bg-second shadow-lg z-2;
|
||||
@@ -667,9 +644,6 @@ provide('currentPractice', currentPractice)
|
||||
}
|
||||
|
||||
.arrow {
|
||||
position: absolute;
|
||||
top: -40%;
|
||||
left: 50%;
|
||||
cursor: pointer;
|
||||
transition: all 0.5s;
|
||||
transform: rotate(-90deg);
|
||||
@@ -677,7 +651,6 @@ provide('currentPractice', currentPractice)
|
||||
font-size: 1.2rem;
|
||||
|
||||
&.down {
|
||||
top: -70%;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,11 +846,10 @@ $translate-lh: 3.2;
|
||||
$article-lh: 2.4;
|
||||
|
||||
.typing-article {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
color: var(--color-article);
|
||||
width: var(--article-width);
|
||||
font-size: 1.6rem;
|
||||
margin-bottom: 10rem;
|
||||
|
||||
header {
|
||||
word-wrap: break-word;
|
||||
|
||||
@@ -7,6 +7,7 @@ import useTheme from '@/hooks/theme.ts'
|
||||
import BaseIcon from '@/components/BaseIcon.vue'
|
||||
import { useRuntimeStore } from '@/stores/runtime.ts'
|
||||
import { jump2Feedback } from '@/utils'
|
||||
import { watch } from 'vue'
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
const runtimeStore = useRuntimeStore()
|
||||
@@ -17,13 +18,19 @@ const { toggleTheme, getTheme } = useTheme()
|
||||
function goHome() {
|
||||
window.location.href = '/'
|
||||
}
|
||||
watch(
|
||||
() => settingStore.sideExpand,
|
||||
n => {
|
||||
document.documentElement.style.setProperty('--aside-width', n ? '12rem' : '4.5rem')
|
||||
},{immediate: true}
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="layout anim">
|
||||
<!-- 第一个aside 占位用-->
|
||||
<div class="aside space" :class="{ expand: settingStore.sideExpand }"></div>
|
||||
<div class="aside anim fixed" :class="{ expand: settingStore.sideExpand }">
|
||||
<div class="aside space"></div>
|
||||
<div class="aside anim fixed">
|
||||
<div class="top">
|
||||
<Logo v-if="settingStore.sideExpand" />
|
||||
<div class="row" @click="goHome">
|
||||
@@ -42,11 +49,7 @@ function goHome() {
|
||||
<div class="row" @click="router.push('/setting')">
|
||||
<IconFluentSettings20Regular />
|
||||
<span v-if="settingStore.sideExpand">设置</span>
|
||||
<div
|
||||
class="red-point"
|
||||
:class="!settingStore.sideExpand && 'top-1 right-0'"
|
||||
v-if="runtimeStore.isNew"
|
||||
></div>
|
||||
<div class="red-point" :class="!settingStore.sideExpand && 'top-1 right-0'" v-if="runtimeStore.isNew"></div>
|
||||
</div>
|
||||
<div class="row" @click="router.push('/feedback')">
|
||||
<IconFluentCommentEdit20Regular />
|
||||
@@ -88,36 +91,21 @@ function goHome() {
|
||||
<IconFluentHome20Regular />
|
||||
<span>主页</span>
|
||||
</div>
|
||||
<div
|
||||
class="nav-item"
|
||||
@click="router.push('/words')"
|
||||
:class="{ active: $route.path.includes('/words') }"
|
||||
>
|
||||
<div class="nav-item" @click="router.push('/words')" :class="{ active: $route.path.includes('/words') }">
|
||||
<IconFluentTextUnderlineDouble20Regular />
|
||||
<span>单词</span>
|
||||
</div>
|
||||
<div
|
||||
class="nav-item"
|
||||
@click="router.push('/articles')"
|
||||
:class="{ active: $route.path.includes('/articles') }"
|
||||
>
|
||||
<div class="nav-item" @click="router.push('/articles')" :class="{ active: $route.path.includes('/articles') }">
|
||||
<IconFluentBookLetter20Regular />
|
||||
<span>文章</span>
|
||||
</div>
|
||||
<div
|
||||
class="nav-item"
|
||||
@click="router.push('/setting')"
|
||||
:class="{ active: $route.path === '/setting' }"
|
||||
>
|
||||
<div class="nav-item" @click="router.push('/setting')" :class="{ active: $route.path === '/setting' }">
|
||||
<IconFluentSettings20Regular />
|
||||
<span>设置</span>
|
||||
<div class="red-point" v-if="runtimeStore.isNew"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="nav-toggle"
|
||||
@click="settingStore.mobileNavCollapsed = !settingStore.mobileNavCollapsed"
|
||||
>
|
||||
<div class="nav-toggle" @click="settingStore.mobileNavCollapsed = !settingStore.mobileNavCollapsed">
|
||||
<IconFluentChevronDown20Filled v-if="!settingStore.mobileNavCollapsed" />
|
||||
<IconFluentChevronUp20Filled v-else />
|
||||
</div>
|
||||
@@ -146,7 +134,7 @@ function goHome() {
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
box-shadow: rgb(0 0 0 / 3%) 0px 0px 12px 0px;
|
||||
width: 4.5rem;
|
||||
width: var(--aside-width);
|
||||
z-index: 2;
|
||||
|
||||
.row {
|
||||
@@ -167,10 +155,6 @@ function goHome() {
|
||||
font-size: 1.3rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.expand {
|
||||
width: var(--aside-width);
|
||||
}
|
||||
}
|
||||
|
||||
// 移动端顶部菜单栏
|
||||
|
||||
@@ -466,13 +466,13 @@ async function next(isTyping: boolean = true) {
|
||||
}
|
||||
} else if (settingStore.wordPracticeMode === WordPracticeMode.ListenOnly) {
|
||||
if (statStore.stage === WordPracticeStage.ListenNewWord) {
|
||||
nextStage(taskWords.review, '开始听写昨日',true)
|
||||
nextStage(taskWords.review, '开始听写昨日', true)
|
||||
} else if (statStore.stage === WordPracticeStage.ListenReview) {
|
||||
nextStage(taskWords.write, '开始听写之前')
|
||||
} else if (statStore.stage === WordPracticeStage.ListenReviewAll) complete()
|
||||
} else if (settingStore.wordPracticeMode === WordPracticeMode.DictationOnly) {
|
||||
if (statStore.stage === WordPracticeStage.DictationNewWord) {
|
||||
nextStage(taskWords.review, '开始默写昨日',true)
|
||||
nextStage(taskWords.review, '开始默写昨日', true)
|
||||
} else if (statStore.stage === WordPracticeStage.DictationReview) {
|
||||
nextStage(taskWords.write, '开始默写之前')
|
||||
} else if (statStore.stage === WordPracticeStage.DictationReviewAll) complete()
|
||||
@@ -486,13 +486,13 @@ async function next(isTyping: boolean = true) {
|
||||
if (statStore.stage === WordPracticeStage.Shuffle) complete()
|
||||
} else if (settingStore.wordPracticeMode === WordPracticeMode.Review) {
|
||||
if (statStore.stage === WordPracticeStage.IdentifyReview) {
|
||||
nextStage(shuffle(taskWords.review), '开始听写昨日',true)
|
||||
nextStage(shuffle(taskWords.review), '开始听写昨日', true)
|
||||
} else if (statStore.stage === WordPracticeStage.ListenReview) {
|
||||
nextStage(shuffle(taskWords.review), '开始默写昨日')
|
||||
} else if (statStore.stage === WordPracticeStage.DictationReview) {
|
||||
nextStage(taskWords.write, '开始自测之前')
|
||||
} else if (statStore.stage === WordPracticeStage.IdentifyReviewAll) {
|
||||
nextStage(shuffle(taskWords.write), '开始听写之前',true)
|
||||
nextStage(shuffle(taskWords.write), '开始听写之前', true)
|
||||
} else if (statStore.stage === WordPracticeStage.ListenReviewAll) {
|
||||
nextStage(shuffle(taskWords.write), '开始默写之前')
|
||||
} else if (statStore.stage === WordPracticeStage.DictationReviewAll) complete()
|
||||
@@ -732,8 +732,12 @@ useEvents([
|
||||
<template>
|
||||
<PracticeLayout v-loading="loading" panelLeft="var(--word-panel-margin-left)">
|
||||
<template v-slot:practice>
|
||||
<div class="practice-word">
|
||||
<div class="absolute z-1 top-4 w-full" v-if="settingStore.showNearWord">
|
||||
<div class="practice-word mb-50">
|
||||
<div
|
||||
class="fixed z-1 top-4 w-full"
|
||||
style="left: calc(50vw + var(--aside-width) / 2 - var(--toolbar-width) / 2);width:var(--toolbar-width)"
|
||||
v-if="settingStore.showNearWord"
|
||||
>
|
||||
<div class="center gap-2 cursor-pointer float-left" @click="prev" v-if="prevWord">
|
||||
<IconFluentArrowLeft16Regular class="arrow" width="22" />
|
||||
<Tooltip :title="`上一个(${settingStore.shortcutKeyMap[ShortcutKey.Previous]})`">
|
||||
@@ -752,7 +756,6 @@ useEvents([
|
||||
<TypeWord ref="typingRef" :word="word" @wrong="onTypeWrong" @complete="next" @know="onWordKnow" />
|
||||
</div>
|
||||
</template>
|
||||
共{{ Math.ceil(store.sdict.length / store.sdict.perDayStudyNumber) }}组
|
||||
<template v-slot:panel>
|
||||
<Panel>
|
||||
<template v-slot:title>
|
||||
|
||||
@@ -343,7 +343,6 @@ const stages = $computed(() => {
|
||||
.bottom {
|
||||
@apply relative w-full box-border rounded-xl bg-second shadow-lg z-10;
|
||||
padding: 0.2rem var(--space) calc(0.4rem + env(safe-area-inset-bottom, 0px)) var(--space);
|
||||
border: 1px solid var(--color-item-border);
|
||||
|
||||
.stat {
|
||||
@apply flex justify-around gap-[var(--stat-gap)] mt-2;
|
||||
|
||||
@@ -729,11 +729,10 @@ useEvents([
|
||||
.typing-word {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
//overflow: auto;
|
||||
word-break: break-word;
|
||||
position: relative;
|
||||
color: var(--color-font-2);
|
||||
padding-bottom: 8rem;
|
||||
|
||||
.phonetic,
|
||||
.translate {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// uno.config.ts
|
||||
import {defineConfig, presetWind3} from 'unocss'
|
||||
import { defineConfig, presetWind3 } from 'unocss'
|
||||
|
||||
export default defineConfig({
|
||||
shortcuts: {
|
||||
@@ -20,21 +20,20 @@ export default defineConfig({
|
||||
'py-space': 'py-[var(--space)]',
|
||||
'border-item': 'border-[var(--color-item-border)]',
|
||||
'border-item-solid': 'border-1 border-solid border-[var(--color-item-border)]',
|
||||
card: 'rounded-xl p-4 mb-8 shadow-lg box-border relative bg-second',
|
||||
},
|
||||
presets: [
|
||||
presetWind3(),
|
||||
],
|
||||
presets: [presetWind3()],
|
||||
// 自定义断点
|
||||
theme: {
|
||||
breakpoints: {
|
||||
'xs': '480px', // 自定义小断点
|
||||
'sm': '640px',
|
||||
'md': '768px',
|
||||
'lg': '1024px',
|
||||
'xl': '1280px',
|
||||
xs: '480px', // 自定义小断点
|
||||
sm: '640px',
|
||||
md: '768px',
|
||||
lg: '1024px',
|
||||
xl: '1280px',
|
||||
'2xl': '1536px',
|
||||
'3xl': '1920px',
|
||||
'4k': '2560px',
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user