save
This commit is contained in:
1
components.d.ts
vendored
1
components.d.ts
vendored
@@ -57,5 +57,6 @@ declare module 'vue' {
|
||||
Word: typeof import('./src/components/Word.vue')['default']
|
||||
WordItem: typeof import('./src/components/WordItem.vue')['default']
|
||||
WordList: typeof import('./src/components/WordList.vue')['default']
|
||||
WordListModal: typeof import('./src/components/WordListModal.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ useEventListener('keyup', (e: KeyboardEvent) => {
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors.scss";
|
||||
@import "@/assets/css/variable";
|
||||
|
||||
.main-page {
|
||||
position: absolute;
|
||||
|
||||
@@ -444,7 +444,7 @@ html, body {
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="scss">
|
||||
@import "assets/css/colors";
|
||||
@import "assets/css/variable";
|
||||
|
||||
.mobile {
|
||||
width: 100vw;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//@import '/node_modules/element-plus/dist/index.css';
|
||||
@import "/node_modules/hover.css";
|
||||
@import "colors";
|
||||
@import "variable.scss";
|
||||
@import "anim";
|
||||
|
||||
:root {
|
||||
|
||||
@@ -30,7 +30,7 @@ onMounted(() => {
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors.scss";
|
||||
@import "@/assets/css/variable";
|
||||
|
||||
#BatchAddArticle {
|
||||
width: 100vw;
|
||||
|
||||
@@ -1,53 +1,81 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {Word} from "@/types.ts"
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
|
||||
defineProps<{
|
||||
list: Word[][],
|
||||
activeIndex: number
|
||||
activeIndex?: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['update:activeIndex'])
|
||||
|
||||
function next() {
|
||||
}
|
||||
const emit = defineEmits<{
|
||||
'update:activeIndex': [index: number]
|
||||
showWord: [list: any[]]
|
||||
}>()
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="list">
|
||||
<div class="item" :class="activeIndex === index && 'active'"
|
||||
v-for="(item,index) in list" @click="$emit('update:activeIndex', index)">
|
||||
<div class="title">第{{ index + 1 }}章 {{ item.length }}词</div>
|
||||
<div class="item"
|
||||
:class="activeIndex === index && 'active'"
|
||||
v-for="(item,index) in list"
|
||||
@click="emit('update:activeIndex', index)">
|
||||
<input type="radio" :checked="activeIndex === index">
|
||||
<div class="title">
|
||||
<div>第{{ index + 1 }}章</div>
|
||||
<div class="count"
|
||||
@click.stop="emitter.emit(EventKey.openWordListModal,{title:`第${index + 1}章`,list:item})"
|
||||
>{{ item.length }}词
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors";
|
||||
@import "@/assets/css/variable.scss";
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 $space;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
box-sizing: border-box;
|
||||
gap: 10rem;
|
||||
//padding-right: 10rem;
|
||||
|
||||
.item {
|
||||
cursor: pointer;
|
||||
margin-bottom: 10rem;
|
||||
padding: 10rem;
|
||||
border-radius: 10rem;
|
||||
padding: 15rem;
|
||||
background: var(--color-item-bg);
|
||||
color: var(--color-font-1);
|
||||
|
||||
display: flex;
|
||||
gap: 10rem;
|
||||
border-radius: 8rem;
|
||||
border-bottom: 1px solid #e1e1e1;
|
||||
|
||||
&.active {
|
||||
background: var(--color-item-active);
|
||||
color: var(--color-font-active-1);
|
||||
|
||||
.count {
|
||||
border-bottom: 2px solid white !important;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
gap: 10rem;
|
||||
|
||||
.count {
|
||||
cursor: pointer;
|
||||
border-bottom: 2px solid var(--color-item-active);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors";
|
||||
@import "@/assets/css/variable.scss";
|
||||
|
||||
$w: 22rem;
|
||||
.icon-wrapper {
|
||||
|
||||
@@ -138,7 +138,7 @@ async function cancel() {
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors";
|
||||
@import "@/assets/css/variable.scss";
|
||||
|
||||
$modal-mask-bg: rgba(#000, .45);
|
||||
$radius: 24rem;
|
||||
|
||||
@@ -79,7 +79,7 @@ onUnmounted(() => {
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors.scss";
|
||||
@import "@/assets/css/variable";
|
||||
|
||||
.footer {
|
||||
width: var(--toolbar-width);
|
||||
|
||||
@@ -182,7 +182,7 @@ function changeIndex(i: number, dict: Dict) {
|
||||
</Transition>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors";
|
||||
@import "@/assets/css/variable.scss";
|
||||
|
||||
$width: 20vw;
|
||||
$header-height: 50rem;
|
||||
|
||||
@@ -49,6 +49,8 @@ const volumeIconRef: any = $ref()
|
||||
watch(() => props.words, () => {
|
||||
data.words = props.words
|
||||
data.index = props.index
|
||||
data.originWrongWords = []
|
||||
data.wrongWords = []
|
||||
|
||||
practiceStore.wrongWords = []
|
||||
practiceStore.repeatNumber = 0
|
||||
@@ -320,7 +322,7 @@ useOnKeyboardEventListener(onKeyDown, onKeyUp)
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors.scss";
|
||||
@import "@/assets/css/variable";
|
||||
|
||||
.type-word {
|
||||
flex: 1;
|
||||
@@ -343,6 +345,7 @@ useOnKeyboardEventListener(onKeyDown, onKeyUp)
|
||||
.word {
|
||||
div {
|
||||
font-size: 24rem;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
div:last-child {
|
||||
|
||||
@@ -44,7 +44,7 @@ onMounted(() => {
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors";
|
||||
@import "@/assets/css/variable.scss";
|
||||
|
||||
$w: 100rem;
|
||||
$w2: calc($w / 2);
|
||||
|
||||
@@ -19,6 +19,9 @@ import VolumeIcon from "@/components/VolumeIcon.vue";
|
||||
import {ActivityCalendar} from "vue-activity-calendar";
|
||||
import "vue-activity-calendar/style.css";
|
||||
import {usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
import ChapterList from "@/components/ChapterList.vue";
|
||||
import WordListModal from "@/components/WordListModal.vue";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
|
||||
const store = useBaseStore()
|
||||
|
||||
@@ -42,7 +45,6 @@ const options = [
|
||||
{id: 'code', name: 'Code', flag: codeFlag},
|
||||
]
|
||||
|
||||
const playWordAudio = usePlayWordAudio()
|
||||
let currentLanguage = $ref('en')
|
||||
let currentSelectDict: Dict = $ref(cloneDeep(store.currentDict))
|
||||
let step = $ref(1)
|
||||
@@ -144,6 +146,13 @@ let radio1 = $ref('')
|
||||
function clickEvent(e) {
|
||||
console.log('e', e)
|
||||
}
|
||||
|
||||
let showModal = $ref(false)
|
||||
|
||||
function showWord(list: Word[]) {
|
||||
console.log('list', list)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -197,11 +206,11 @@ function clickEvent(e) {
|
||||
<div class="detail">
|
||||
<div class="name">{{ currentSelectDict.name }}</div>
|
||||
<div class="desc">{{ currentSelectDict.description }}</div>
|
||||
<div class="num">总词汇:{{ currentSelectDict.length }}词</div>
|
||||
<div class="num">{{
|
||||
currentSelectDict.chapterWords.length
|
||||
}}章(每章{{ currentSelectDict.chapterWordNumber }}词)
|
||||
<div class="num"
|
||||
@click="emitter.emit(EventKey.openWordListModal,{title:'所有单词',list:currentSelectDict.words})">
|
||||
总词汇:<span class="count">{{ currentSelectDict.length }}词</span>
|
||||
</div>
|
||||
|
||||
<div class="num">开始日期:-</div>
|
||||
<div class="num">花费时间:-</div>
|
||||
<div class="num">累积错误:-</div>
|
||||
@@ -212,7 +221,7 @@ function clickEvent(e) {
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting">
|
||||
<div class="title">学习设置</div>
|
||||
<div class="common-title">学习设置</div>
|
||||
<div class="row">
|
||||
<div class="label">每章单词数</div>
|
||||
<el-slider :min="10"
|
||||
@@ -284,30 +293,18 @@ function clickEvent(e) {
|
||||
</div>
|
||||
</div>
|
||||
<div class="other">
|
||||
<virtual-list class="virtual-list"
|
||||
:keeps="20"
|
||||
data-key="name"
|
||||
:data-sources="currentSelectDict.words"
|
||||
:estimate-size="85"
|
||||
item-class="dict-virtual-item"
|
||||
>
|
||||
<template #={source}>
|
||||
<div class="left">
|
||||
<div class="title">
|
||||
<span class="word">{{ source.name }}</span>
|
||||
<span class="phonetic">{{ source.usphone }}</span>
|
||||
</div>
|
||||
<div class="translate">{{ source.trans.join(';') }}</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<VolumeIcon @click="playWordAudio(source.name)"></VolumeIcon>
|
||||
<Icon icon="fluent:delete-28-regular" width="20" color="#929596"/>
|
||||
</div>
|
||||
</template>
|
||||
</virtual-list>
|
||||
<div class="common-title">
|
||||
章节列表:共{{
|
||||
currentSelectDict.chapterWords.length
|
||||
}}章(每章{{ currentSelectDict.chapterWordNumber }}词)
|
||||
</div>
|
||||
<ChapterList
|
||||
@showWord="showWord"
|
||||
v-model:active-index="currentSelectDict.chapterIndex"
|
||||
:list="currentSelectDict.chapterWords"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="activity">
|
||||
<div v-if="false" class="activity">
|
||||
<ActivityCalendar
|
||||
:data="[{ date: '2023-05-22', count: 5 }]"
|
||||
:width="40"
|
||||
@@ -329,16 +326,16 @@ function clickEvent(e) {
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
<WordListModal/>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors";
|
||||
@import "@/assets/css/variable.scss";
|
||||
|
||||
$modal-mask-bg: rgba(#000, .15);
|
||||
$radius: 16rem;
|
||||
$time: 0.3s;
|
||||
$header-height: 60rem;
|
||||
$footer-height: 40rem;
|
||||
|
||||
.slide {
|
||||
width: 1100rem;
|
||||
@@ -405,7 +402,6 @@ $footer-height: 40rem;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
padding-right: $space;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -443,17 +439,24 @@ $footer-height: 40rem;
|
||||
position: relative;
|
||||
gap: $space;
|
||||
|
||||
.common-title {
|
||||
font-size: 20rem;
|
||||
color: gray;
|
||||
text-align: center;
|
||||
margin-bottom: 10rem;
|
||||
}
|
||||
|
||||
.detail {
|
||||
overflow: auto;
|
||||
flex: 3;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rem;
|
||||
cursor: pointer;
|
||||
padding: 15rem;
|
||||
min-height: 100rem;
|
||||
position: relative;
|
||||
border-radius: 10rem;
|
||||
background: var(--color-item-bg);
|
||||
background: var(--color-second-bg);
|
||||
color: var(--color-font-1);
|
||||
font-size: 14rem;
|
||||
|
||||
@@ -466,22 +469,22 @@ $footer-height: 40rem;
|
||||
font-size: 18rem;
|
||||
margin-bottom: 30rem;
|
||||
}
|
||||
|
||||
.count {
|
||||
cursor: pointer;
|
||||
border-bottom: 2px solid var(--color-item-active);
|
||||
}
|
||||
}
|
||||
|
||||
.setting {
|
||||
overflow: auto;
|
||||
flex: 5;
|
||||
background: white;
|
||||
border-radius: 10rem;
|
||||
background: var(--color-item-bg);
|
||||
background: var(--color-second-bg);
|
||||
color: var(--color-font-1);
|
||||
padding: 15rem;
|
||||
|
||||
.title {
|
||||
font-size: 20rem;
|
||||
color: gray;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -494,15 +497,12 @@ $footer-height: 40rem;
|
||||
|
||||
.other {
|
||||
flex: 5;
|
||||
background: white;
|
||||
border-radius: 10rem;
|
||||
background: var(--color-item-bg);
|
||||
background: var(--color-second-bg);
|
||||
color: var(--color-font-1);
|
||||
padding: 10rem;
|
||||
|
||||
.word-list {
|
||||
height: calc(100% - $footer-height);
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,71 +512,12 @@ $footer-height: 40rem;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 10rem;
|
||||
box-sizing: content-box;
|
||||
height: $footer-height;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
gap: $space;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
@import "@/assets/css/colors";
|
||||
|
||||
.virtual-list {
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.dict-virtual-item {
|
||||
background: var(--color-header-bg);
|
||||
border-radius: 6rem;
|
||||
padding: 8rem 12rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
transition: all .3s;
|
||||
color: var(--color-font-1);
|
||||
|
||||
&.active {
|
||||
background: $second;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
//background: $dark-main-bg;
|
||||
//background: $item-hover;
|
||||
background: rgb(226, 226, 226);
|
||||
}
|
||||
|
||||
.left {
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rem;
|
||||
|
||||
.word {
|
||||
font-size: 24rem;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.phonetic {
|
||||
font-size: 14rem;
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 5rem;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -42,7 +42,7 @@ const emit = defineEmits([
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors.scss";
|
||||
@import "@/assets/css/variable";
|
||||
|
||||
.feedback-modal {
|
||||
width: 500rem;
|
||||
|
||||
@@ -230,7 +230,7 @@ useWatchAllSound()
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors.scss";
|
||||
@import "@/assets/css/variable";
|
||||
|
||||
.setting-modal {
|
||||
width: 40vw;
|
||||
|
||||
@@ -108,7 +108,7 @@ watch(() => settingStore.showToolbar, n => {
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors.scss";
|
||||
@import "@/assets/css/variable";
|
||||
|
||||
header {
|
||||
width: var(--toolbar-width);
|
||||
|
||||
@@ -41,7 +41,7 @@ const emit = defineEmits<{
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors";
|
||||
@import "@/assets/css/variable.scss";
|
||||
|
||||
.word-item {
|
||||
background: var(--color-header-bg);
|
||||
|
||||
@@ -56,7 +56,7 @@ watch(() => props.list, () => {
|
||||
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/colors";
|
||||
@import "@/assets/css/variable.scss";
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
|
||||
130
src/components/WordListModal.vue
Normal file
130
src/components/WordListModal.vue
Normal file
@@ -0,0 +1,130 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import VolumeIcon from "@/components/VolumeIcon.vue";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import Modal from "@/components/Modal/Modal.vue";
|
||||
import {$ref} from "vue/macros";
|
||||
import {onMounted, onUnmounted} from "vue";
|
||||
import {usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
|
||||
let show = $ref(false)
|
||||
let list = $ref([])
|
||||
let title = $ref('')
|
||||
const playWordAudio = usePlayWordAudio()
|
||||
|
||||
onMounted(() => {
|
||||
emitter.on(EventKey.openWordListModal, (val) => {
|
||||
list = val.list
|
||||
title = val.title
|
||||
show = true
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.off(EventKey.openWordListModal)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
:title="title"
|
||||
v-model="show">
|
||||
<div class="all-word">
|
||||
<virtual-list class="virtual-list"
|
||||
:keeps="20"
|
||||
data-key="name"
|
||||
:data-sources="list"
|
||||
:estimate-size="85"
|
||||
item-class="dict-virtual-item"
|
||||
>
|
||||
<template #={source}>
|
||||
<div class="left">
|
||||
<div class="title">
|
||||
<span class="word">{{ source.name }}</span>
|
||||
<span class="phonetic">{{ source.usphone }}</span>
|
||||
</div>
|
||||
<div class="translate">{{ source.trans.join(';') }}</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<VolumeIcon @click="playWordAudio(source.name)"></VolumeIcon>
|
||||
<Icon icon="fluent:delete-28-regular" width="20" color="#929596"/>
|
||||
</div>
|
||||
</template>
|
||||
</virtual-list>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/style";
|
||||
|
||||
.all-word {
|
||||
padding: $space;
|
||||
padding-top: 0;
|
||||
width: 400rem;
|
||||
height: 75vh;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
@import "@/assets/css/variable.scss";
|
||||
|
||||
.virtual-list {
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.dict-virtual-item {
|
||||
background: var(--color-header-bg);
|
||||
border-radius: 6rem;
|
||||
padding: 8rem 12rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
transition: all .3s;
|
||||
color: var(--color-font-1);
|
||||
margin-bottom: 10rem;
|
||||
|
||||
&.active {
|
||||
background: $second;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
//background: $dark-main-bg;
|
||||
//background: $item-hover;
|
||||
background: rgb(226, 226, 226);
|
||||
}
|
||||
|
||||
.left {
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rem;
|
||||
|
||||
.word {
|
||||
font-size: 24rem;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.phonetic {
|
||||
font-size: 14rem;
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
.translate {
|
||||
font-size: 14rem;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 5rem;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -4,6 +4,7 @@ export const emitter = mitt()
|
||||
export const EventKey = {
|
||||
resetWord: 'resetWord',
|
||||
openStatModal: 'openStatModal',
|
||||
openWordListModal: 'openWordListModal',
|
||||
closeOther: 'closeOther',
|
||||
keydown: 'keydown',
|
||||
keyup: 'keyup',
|
||||
|
||||
Reference in New Issue
Block a user