remove surplus list
This commit is contained in:
8
components.d.ts
vendored
8
components.d.ts
vendored
@@ -8,17 +8,13 @@ export {}
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
Add: typeof import('./src/components/toolbar/Add.vue')['default']
|
||||
ArticleList2: typeof import('./src/components/list/ArticleList2.vue')['default']
|
||||
ArticleList3: typeof import('./src/components/list/ArticleList3.vue')['default']
|
||||
ArticleList4: typeof import('./src/components/list2/ArticleList4.vue')['default']
|
||||
Backgorund: typeof import('./src/components/Backgorund.vue')['default']
|
||||
BaseButton: typeof import('./src/components/BaseButton.vue')['default']
|
||||
BaseIcon: typeof import('./src/components/BaseIcon.vue')['default']
|
||||
BaseList: typeof import('./src/components/list2/BaseList.vue')['default']
|
||||
ChapterList: typeof import('./src/components/list/ChapterList.vue')['default']
|
||||
ChapterName: typeof import('./src/components/toolbar/ChapterName.vue')['default']
|
||||
Close: typeof import('./src/components/icon/Close.vue')['default']
|
||||
CommonWordList: typeof import('./src/components/list/CommonWordList.vue')['default']
|
||||
Dialog: typeof import('./src/components/dialog/Dialog.vue')['default']
|
||||
DictDiglog: typeof import('./src/components/dialog/DictDiglog.vue')['default']
|
||||
DictGroup: typeof import('./src/components/toolbar/DictGroup.vue')['default']
|
||||
@@ -49,7 +45,6 @@ declare module 'vue' {
|
||||
IconWrapper: typeof import('./src/components/IconWrapper.vue')['default']
|
||||
Input: typeof import('./src/components/Input.vue')['default']
|
||||
List: typeof import('./src/components/list/List.vue')['default']
|
||||
ListItem: typeof import('./src/components/list/ListItem.vue')['default']
|
||||
MiniDialog: typeof import('./src/components/dialog/MiniDialog.vue')['default']
|
||||
PopConfirm: typeof import('./src/components/PopConfirm.vue')['default']
|
||||
RepeatSetting: typeof import('./src/components/toolbar/RepeatSetting.vue')['default']
|
||||
@@ -61,11 +56,8 @@ declare module 'vue' {
|
||||
Toolbar: typeof import('./src/components/toolbar/index.vue')['default']
|
||||
Tooltip: typeof import('./src/components/Tooltip.vue')['default']
|
||||
TranslateSetting: typeof import('./src/components/toolbar/TranslateSetting.vue')['default']
|
||||
VirtualWordList: typeof import('./src/components/list/VirtualWordList.vue')['default']
|
||||
VirtualWordList2: typeof import('./src/components/list/VirtualWordList2.vue')['default']
|
||||
VolumeIcon: typeof import('./src/components/icon/VolumeIcon.vue')['default']
|
||||
VolumeSetting: typeof import('./src/components/toolbar/VolumeSetting.vue')['default']
|
||||
WordItem: typeof import('./src/components/list/WordItem.vue')['default']
|
||||
WordList: typeof import('./src/components/list2/WordList.vue')['default']
|
||||
WordListDialog: typeof import('./src/components/dialog/WordListDialog.vue')['default']
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import {Icon} from "@iconify/vue";
|
||||
defineProps<{
|
||||
title?: string,
|
||||
icon: string,
|
||||
className?: string
|
||||
}>()
|
||||
|
||||
defineEmits(['click'])
|
||||
@@ -15,7 +14,7 @@ defineEmits(['click'])
|
||||
|
||||
<template>
|
||||
<Tooltip :title="title">
|
||||
<IconWrapper :class="className">
|
||||
<IconWrapper v-bind="$attrs">
|
||||
<Icon @click.stop="$emit('click')" :icon="icon"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
|
||||
@@ -52,28 +52,40 @@ async function selectDict(val: { dict: DictResource | Dict, index: number }) {
|
||||
...cloneDeep(DefaultDict),
|
||||
...item,
|
||||
})
|
||||
runtimeStore.editDict.id = nanoid(6)
|
||||
//设置默认章节单词数
|
||||
runtimeStore.editDict.chapterWordNumber = settingStore.chapterWordNumber
|
||||
}
|
||||
|
||||
if ([DictType.collect, DictType.simple, DictType.wrong].includes(runtimeStore.editDict.type)) {
|
||||
} else {
|
||||
let url = `./dicts/${runtimeStore.editDict.language}/${runtimeStore.editDict.type}/${runtimeStore.editDict.translateLanguage}/${runtimeStore.editDict.url}`;
|
||||
if (runtimeStore.editDict.type === DictType.word) {
|
||||
if (!runtimeStore.editDict.originWords.length) {
|
||||
let r = await fetch(url)
|
||||
let v = await r.json()
|
||||
runtimeStore.editDict.originWords = cloneDeep(v)
|
||||
changeSort(runtimeStore.editDict.sort)
|
||||
//如果不是自定义词典,并且有url地址才去下载
|
||||
if (!runtimeStore.editDict.isCustom && runtimeStore.editDict.url) {
|
||||
let url = `./dicts/${runtimeStore.editDict.language}/${runtimeStore.editDict.type}/${runtimeStore.editDict.translateLanguage}/${runtimeStore.editDict.url}`;
|
||||
if (runtimeStore.editDict.type === DictType.word) {
|
||||
if (!runtimeStore.editDict.originWords.length) {
|
||||
let r = await fetch(url)
|
||||
let v = await r.json()
|
||||
v.map(s => {
|
||||
s.id = nanoid(6)
|
||||
})
|
||||
runtimeStore.editDict.originWords = cloneDeep(v)
|
||||
changeSort(runtimeStore.editDict.sort)
|
||||
} else {
|
||||
runtimeStore.editDict.length = runtimeStore.editDict.words.length + runtimeStore.editDict.residueWords.length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (runtimeStore.editDict.type === DictType.article) {
|
||||
if (!runtimeStore.editDict.articles.length) {
|
||||
let r = await fetch(url)
|
||||
let v = await r.json()
|
||||
runtimeStore.editDict.articles = cloneDeep(v.map(s => {
|
||||
s.id = nanoid(6)
|
||||
return s
|
||||
}))
|
||||
if (runtimeStore.editDict.type === DictType.article) {
|
||||
if (!runtimeStore.editDict.articles.length) {
|
||||
let r = await fetch(url)
|
||||
let v = await r.json()
|
||||
v.map(s => {
|
||||
s.id = nanoid(6)
|
||||
})
|
||||
runtimeStore.editDict.articles = cloneDeep(v)
|
||||
} else {
|
||||
runtimeStore.editDict.length = runtimeStore.editDict.articles.length
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,24 +133,13 @@ function changeSort(v) {
|
||||
resetChapterList()
|
||||
}
|
||||
|
||||
function editDict() {
|
||||
show = false
|
||||
setTimeout(() => {
|
||||
router.push({path: '/dict', query: {type: 'editDict'}})
|
||||
}, 500)
|
||||
}
|
||||
|
||||
let wordListRef: any = $ref()
|
||||
|
||||
function add() {
|
||||
function option(type: string) {
|
||||
show = false
|
||||
setTimeout(() => {
|
||||
router.push({path: '/dict', query: {type: 'addWordOrArticle'}})
|
||||
router.push({path: '/dict', query: {type: type}})
|
||||
}, 500)
|
||||
if (dictIsArticle) {
|
||||
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
/**/
|
||||
@@ -215,9 +216,10 @@ function showWordListModal(val: { item: Word, index: number }) {
|
||||
<div class="left-column">
|
||||
<BaseIcon
|
||||
v-if="![DictType.collect,DictType.wrong,DictType.simple].includes(runtimeStore.editDict.type)"
|
||||
class-name="edit-icon"
|
||||
class="edit-icon"
|
||||
title="编辑词典"
|
||||
icon="tabler:edit"
|
||||
@click='editDict'
|
||||
@click='option("editDict")'
|
||||
/>
|
||||
<div class="name">{{ runtimeStore.editDict.name }}</div>
|
||||
<div class="desc">{{ runtimeStore.editDict.description }}</div>
|
||||
@@ -230,7 +232,8 @@ function showWordListModal(val: { item: Word, index: number }) {
|
||||
}}词</span>
|
||||
</div>
|
||||
<BaseIcon icon="mi:add"
|
||||
@click='add'
|
||||
@click='option("addWordOrArticle")'
|
||||
:title="`添加${dictIsArticle?'文章':'单词'}`"
|
||||
/>
|
||||
</div>
|
||||
<div class="text">开始日期:-</div>
|
||||
@@ -322,7 +325,15 @@ function showWordListModal(val: { item: Word, index: number }) {
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-column">
|
||||
<div class="common-title">{{ dictIsArticle ? '文章' : '章节' }}列表</div>
|
||||
<div class="common-title">
|
||||
<span>{{ dictIsArticle ? '文章' : '章节' }}列表</span>
|
||||
<BaseIcon
|
||||
icon="fluent:notepad-edit-20-regular"
|
||||
@click='option("detail")'
|
||||
style="position: absolute;right: 20rem;"
|
||||
:title="`管理${dictIsArticle?'文章':'章节'}`"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="dictIsArticle">
|
||||
<ArticleList4
|
||||
v-if="runtimeStore.editDict.articles.length"
|
||||
@@ -457,13 +468,13 @@ $header-height: 60rem;
|
||||
padding-right: var(--space);
|
||||
|
||||
.name {
|
||||
font-size: 28rem;
|
||||
margin-bottom: 10rem;
|
||||
font-size: 24rem;
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 18rem;
|
||||
margin-bottom: 30rem;
|
||||
font-size: 16rem;
|
||||
margin-bottom: 20rem;
|
||||
}
|
||||
|
||||
.count {
|
||||
@@ -471,13 +482,9 @@ $header-height: 60rem;
|
||||
border-bottom: 2px solid var(--color-item-active);
|
||||
}
|
||||
|
||||
.edit-icon {
|
||||
|
||||
}
|
||||
|
||||
:deep(.edit-icon) {
|
||||
position: absolute;
|
||||
top: 8rem;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import {$ref} from "vue/macros";
|
||||
import {onMounted, onUnmounted, watch} from "vue";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import VirtualWordList from "@/components/list/VirtualWordList.vue";
|
||||
import WordList from "@/components/list2/WordList.vue";
|
||||
|
||||
let show = $ref(false)
|
||||
let loading = $ref(false)
|
||||
@@ -18,7 +18,7 @@ onMounted(() => {
|
||||
emitter.on(EventKey.openWordListModal, (val: any) => {
|
||||
show = true
|
||||
list = val.list
|
||||
title = val.title
|
||||
title = val.title + `(${list.length}词)`
|
||||
requestIdleCallback(() => {
|
||||
let count = 0
|
||||
if (val.translateLanguage === 'common') {
|
||||
@@ -77,10 +77,10 @@ onUnmounted(() => {
|
||||
:indeterminate="false"
|
||||
:show-text="false"/>
|
||||
</div>
|
||||
<VirtualWordList
|
||||
<WordList
|
||||
class="word-list"
|
||||
:list="list">
|
||||
</VirtualWordList>
|
||||
</WordList>
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -93,6 +93,8 @@ onUnmounted(() => {
|
||||
padding-top: 0;
|
||||
width: 400rem;
|
||||
height: 75vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.progress-wrapper {
|
||||
padding: 0 var(--space);
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import Input from "@/components/Input.vue";
|
||||
import {$computed, $ref} from "vue/macros";
|
||||
import {Article, Word} from "@/types.ts";
|
||||
import ListItem from "@/components/list/ListItem.vue";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {watch} from "vue";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
list: Article[],
|
||||
activeIndex?: number,
|
||||
isActive?: boolean
|
||||
showTranslate?: boolean
|
||||
}>(), {
|
||||
activeIndex: -1,
|
||||
isActive: false
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
selectItem: [val: Article],
|
||||
delSelectItem: [],
|
||||
'update:searchKey': [val: string],
|
||||
'update:list': [list: Article[]],
|
||||
}>()
|
||||
|
||||
let searchKey = $ref('')
|
||||
let localList = $computed({
|
||||
get() {
|
||||
if (searchKey) {
|
||||
return props.list.filter((item: Article) => {
|
||||
//把搜索内容,分词之后,判断是否有这个词,比单纯遍历包含体验更好
|
||||
return searchKey.toLowerCase().split(' ').filter(v => v).some(value => {
|
||||
return item.title.toLowerCase().includes(value) || item.titleTranslate.toLowerCase().includes(value)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
return props.list
|
||||
}
|
||||
},
|
||||
set(newValue) {
|
||||
emit('update:list', newValue)
|
||||
}
|
||||
})
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
|
||||
const listRef: HTMLElement = $ref(null as any)
|
||||
|
||||
function scrollViewToCenter(index: number) {
|
||||
if (index === -1) return
|
||||
listRef.children[index + 1]?.scrollIntoView({block: 'center', behavior: 'smooth'})
|
||||
}
|
||||
|
||||
watch(() => props.activeIndex, (n: any) => {
|
||||
if (settingStore.showPanel) {
|
||||
scrollViewToCenter(n)
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => props.isActive, (n: boolean) => {
|
||||
setTimeout(() => {
|
||||
if (n) scrollViewToCenter(props.activeIndex)
|
||||
}, 300)
|
||||
})
|
||||
|
||||
watch(() => props.list, () => {
|
||||
listRef.scrollTo(0, 0)
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="list" ref="listRef">
|
||||
<div class="search">
|
||||
<Input v-model="searchKey"/>
|
||||
</div>
|
||||
<div class="common-list-item"
|
||||
v-for="(source,index) in localList" :key="index"
|
||||
:class="{active:activeIndex === index}"
|
||||
@click="emit('selectItem',source)"
|
||||
>
|
||||
<div class="left">
|
||||
<div class="title-wrapper">
|
||||
<div class="item-title">
|
||||
<div class="name"> {{ `${index + 1}. ${source.title}` }}</div>
|
||||
</div>
|
||||
<div class="item-sub-title" v-if="source.titleTranslate && showTranslate">
|
||||
<div class="item-translate"> {{ ` ${source.titleTranslate}` }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<slot :source="source" :index="index"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/variable.scss";
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15rem;
|
||||
flex: 1;
|
||||
overflow: overlay;
|
||||
padding: 0 var(--space);
|
||||
|
||||
.search {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.translate {
|
||||
font-size: 16rem;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -1,158 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import Input from "@/components/Input.vue";
|
||||
import {$computed, $ref} from "vue/macros";
|
||||
import {Article, Word} from "@/types.ts";
|
||||
import ListItem from "@/components/list/ListItem.vue";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {watch} from "vue";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
list: Article[],
|
||||
activeIndex?: number,
|
||||
isActive?: boolean
|
||||
showTranslate?: boolean
|
||||
}>(), {
|
||||
list: [],
|
||||
activeIndex: -1,
|
||||
isActive: false,
|
||||
showTranslate:true
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
click: [val: { data: Article, index: number }],
|
||||
delSelectItem: [],
|
||||
'update:searchKey': [val: string],
|
||||
'update:list': [list: Article[]],
|
||||
}>()
|
||||
|
||||
let searchKey = $ref('')
|
||||
let localList = $computed({
|
||||
get() {
|
||||
if (searchKey) {
|
||||
return props.list.filter((item: Article) => {
|
||||
//把搜索内容,分词之后,判断是否有这个词,比单纯遍历包含体验更好
|
||||
return searchKey.toLowerCase().split(' ').filter(v => v).some(value => {
|
||||
return item.title.toLowerCase().includes(value) || item.titleTranslate.toLowerCase().includes(value)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
return props.list
|
||||
}
|
||||
},
|
||||
set(newValue) {
|
||||
emit('update:list', newValue)
|
||||
}
|
||||
})
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
|
||||
const listRef: HTMLElement = $ref(null as any)
|
||||
|
||||
// function scrollViewToCenter(index: number) {
|
||||
// if (index === -1) return
|
||||
// listRef.children[index + 1]?.scrollIntoView({block: 'center', behavior: 'smooth'})
|
||||
// }
|
||||
//
|
||||
// watch(() => props.activeIndex, (n: any) => {
|
||||
// if (settingStore.showPanel) {
|
||||
// scrollViewToCenter(n)
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// watch(() => props.isActive, (n: boolean) => {
|
||||
// setTimeout(() => {
|
||||
// if (n) scrollViewToCenter(props.activeIndex)
|
||||
// }, 300)
|
||||
// })
|
||||
|
||||
watch(() => props.list, () => {
|
||||
// listRef.scrollTo(0, 0)
|
||||
})
|
||||
|
||||
function scrollToBottom() {
|
||||
listRef.scrollToBottom()
|
||||
}
|
||||
|
||||
function scrollToItem(index: number) {
|
||||
listRef.scrollToItem(index)
|
||||
}
|
||||
|
||||
defineExpose({scrollToBottom, scrollToItem})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="list">
|
||||
<div class="search">
|
||||
<Input v-model="searchKey"/>
|
||||
</div>
|
||||
<DynamicScroller
|
||||
:items="list"
|
||||
ref="listRef"
|
||||
:min-item-size="90"
|
||||
class="scroller"
|
||||
>
|
||||
<template v-slot="{ item, index, active }">
|
||||
<DynamicScrollerItem
|
||||
:item="item"
|
||||
:active="active"
|
||||
:size-dependencies="[
|
||||
item.id,
|
||||
]"
|
||||
:data-index="index"
|
||||
>
|
||||
<div class="list-item-wrapper">
|
||||
<div class="common-list-item"
|
||||
:class="{active:activeIndex === index}"
|
||||
@click="emit('click',{data:item,index})"
|
||||
>
|
||||
<div class="left">
|
||||
<slot name="prefix" :data="item" :index="index"></slot>
|
||||
<div class="title-wrapper">
|
||||
<div class="item-title">
|
||||
<div class="name"> {{ `${index + 1}. ${item.title}` }}</div>
|
||||
</div>
|
||||
<div class="item-sub-title" v-if="item.titleTranslate && showTranslate">
|
||||
<div class="item-translate"> {{ ` ${item.titleTranslate}` }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<slot :data="item" :index="index"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DynamicScrollerItem>
|
||||
</template>
|
||||
</DynamicScroller>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/variable.scss";
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15rem;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
|
||||
.search {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 0 var(--space);
|
||||
}
|
||||
|
||||
.translate {
|
||||
font-size: 16rem;
|
||||
}
|
||||
|
||||
.scroller {
|
||||
flex: 1;
|
||||
padding: 0 var(--space);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,108 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {Dict, Word} from "@/types.ts"
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
import {$computed} from "vue/macros";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
dict: Dict,
|
||||
activeIndex?: number
|
||||
isArticle?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:activeIndex': [index: number]
|
||||
}>()
|
||||
|
||||
const runtimeStore = useRuntimeStore()
|
||||
|
||||
const list: any[] = $computed(() => {
|
||||
if (props.isArticle) return props.dict.articles
|
||||
return props.dict.chapterWords
|
||||
})
|
||||
|
||||
|
||||
function showWordListModal(index: number, item: Word[]) {
|
||||
emitter.emit(EventKey.openWordListModal, {
|
||||
title: `第${index + 1}章`,
|
||||
translateLanguage: runtimeStore.editDict.translateLanguage,
|
||||
list: item
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="list">
|
||||
<div class="common-list-item"
|
||||
:class="activeIndex === index && 'active'"
|
||||
v-for="(item,index) in list"
|
||||
@click="emit('update:activeIndex', index)">
|
||||
<div class="flex gap10">
|
||||
<input type="radio" :checked="activeIndex === index">
|
||||
<div class="left">
|
||||
<div class="title-wrapper">
|
||||
<template v-if="isArticle">
|
||||
<div class="item-title"
|
||||
@click.stop="emitter.emit(EventKey.openArticleListModal,item)"
|
||||
>{{ index + 1 }}. {{ item.title }}
|
||||
</div>
|
||||
<div class="item-sub-title" v-if="item.titleTranslate"> {{ item.titleTranslate }}</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="item-title"
|
||||
@click.stop="showWordListModal(index,item)"
|
||||
>第{{ index + 1 }}章 {{ item.length }}词
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/variable";
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
box-sizing: border-box;
|
||||
gap: 10rem;
|
||||
padding: 0 var(--space);
|
||||
//padding-right: 10rem;
|
||||
|
||||
.common-list-item {
|
||||
|
||||
input {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
transition: all .3s;
|
||||
cursor: pointer;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
|
||||
:deep(.del) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.item-title {
|
||||
border-bottom: 2px solid gray !important;
|
||||
}
|
||||
|
||||
:deep(.del) {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,91 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import {Word} from "../../types.ts";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
import {watch} from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
list: Word[],
|
||||
activeIndex?: number,
|
||||
isActive?: boolean
|
||||
showTranslate?: boolean
|
||||
showWord?: boolean
|
||||
}>(), {
|
||||
activeIndex: -1,
|
||||
isActive: false,
|
||||
showTranslate: true,
|
||||
showWord: true
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: [val: { word: Word, index: number }],
|
||||
}>()
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
|
||||
const listRef: HTMLElement = $ref(null as any)
|
||||
|
||||
function scrollViewToCenter(index: number) {
|
||||
if (index === -1) return
|
||||
listRef.children[index]?.scrollIntoView({block: 'center', behavior: 'smooth'})
|
||||
}
|
||||
|
||||
watch(() => props.activeIndex, (n: any) => {
|
||||
if (settingStore.showPanel) {
|
||||
scrollViewToCenter(n)
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => props.isActive, (n: boolean) => {
|
||||
setTimeout(() => {
|
||||
if (n) scrollViewToCenter(props.activeIndex)
|
||||
}, 300)
|
||||
})
|
||||
|
||||
watch(() => props.list, () => {
|
||||
listRef.scrollTo(0, 0)
|
||||
})
|
||||
|
||||
const playWordAudio = usePlayWordAudio()
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="common-list" ref="listRef">
|
||||
<div class="common-list-item"
|
||||
v-for="(source,index) in list" :key="index"
|
||||
:class="{active:activeIndex === index}"
|
||||
@click="emit('change',{word:source,index})"
|
||||
>
|
||||
<div class="left">
|
||||
<div class="title-wrapper">
|
||||
<div class="item-title">
|
||||
<span class="word" :class="!showWord && 'text-shadow'">{{ source.name }}</span>
|
||||
<span class="phonetic">{{ source.usphone }}</span>
|
||||
<VolumeIcon class="volume" @click="playWordAudio(source.name)"></VolumeIcon>
|
||||
</div>
|
||||
<div class="item-sub-title" v-if="source.trans.length && showTranslate">
|
||||
<div v-for="item in source.trans">{{ item }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<slot :word="source" :index="index"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/variable";
|
||||
|
||||
.common-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15rem;
|
||||
flex: 1;
|
||||
overflow: overlay;
|
||||
padding: 0 var(--space);
|
||||
}
|
||||
</style>
|
||||
@@ -1,126 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
|
||||
defineProps<{
|
||||
showVolume?: boolean,
|
||||
showDel?: boolean,
|
||||
active?: boolean
|
||||
isCollect?: boolean
|
||||
isSimple?: boolean
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
toggleSimple: [],
|
||||
toggleCollect: [],
|
||||
del: [],
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="list-item"
|
||||
:class="{active}"
|
||||
>
|
||||
<div class="left">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div class="right">
|
||||
<BaseIcon
|
||||
v-if="showDel"
|
||||
class-name="del"
|
||||
@click="$emit('del')"
|
||||
title="移除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
<template v-else>
|
||||
<BaseIcon
|
||||
v-if="!isCollect"
|
||||
class-name="collect"
|
||||
@click="$emit('toggleCollect')"
|
||||
title="收藏" icon="ph:star"/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class-name="fill"
|
||||
@click="$emit('toggleCollect')"
|
||||
title="取消收藏" icon="ph:star-fill"/>
|
||||
|
||||
|
||||
<BaseIcon
|
||||
v-if="!isSimple"
|
||||
class-name="easy"
|
||||
@click="$emit('toggleSimple')"
|
||||
title="标记为简单词"
|
||||
icon="material-symbols:check-circle-outline-rounded"/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class-name="fill"
|
||||
@click="$emit('toggleSimple')"
|
||||
title="取消标记简单词"
|
||||
icon="material-symbols:check-circle-rounded"/>
|
||||
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.list-item {
|
||||
.left {
|
||||
display: flex;
|
||||
gap: 10rem;
|
||||
flex-direction: column;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5rem;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
:deep(.collect) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
:deep(.easy) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
:deep(.collect) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
:deep(.easy) {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
|
||||
:deep(.sub-title) {
|
||||
//color: black;
|
||||
}
|
||||
|
||||
:deep(.title) {
|
||||
//color: black;
|
||||
}
|
||||
|
||||
$c: #E6A23C;
|
||||
|
||||
:deep(.collect) {
|
||||
color: $c;
|
||||
}
|
||||
|
||||
:deep(.fill) {
|
||||
color: $c;
|
||||
}
|
||||
|
||||
:deep(.easy) {
|
||||
color: $c;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,108 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import {Word} from "../../types.ts";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
import {watch} from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
list: Word[],
|
||||
activeIndex?: number,
|
||||
isActive?: boolean
|
||||
showTranslate?: boolean
|
||||
showWord?: boolean
|
||||
}>(), {
|
||||
activeIndex: -1,
|
||||
isActive: false,
|
||||
showTranslate: true,
|
||||
showWord: true
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: [val: { word: Word, index: number }],
|
||||
}>()
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
const listRef: any = $ref()
|
||||
|
||||
function scrollViewToCenter(index: number) {
|
||||
if (index === -1) return
|
||||
listRef.scrollToIndex(index)
|
||||
// listRef.children[index]?.scrollIntoView({block: 'center', behavior: 'smooth'})
|
||||
}
|
||||
|
||||
watch(() => props.activeIndex, (n: any) => {
|
||||
if (settingStore.showPanel) {
|
||||
scrollViewToCenter(n)
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => props.isActive, (n: boolean) => {
|
||||
setTimeout(() => {
|
||||
if (n) scrollViewToCenter(props.activeIndex)
|
||||
}, 300)
|
||||
})
|
||||
|
||||
// watch(() => props.list, () => {
|
||||
// listRef.scrollTo(0, 0)
|
||||
// })
|
||||
|
||||
const playWordAudio = usePlayWordAudio()
|
||||
|
||||
function reset() {
|
||||
listRef.reset()
|
||||
}
|
||||
|
||||
function scrollToBottom() {
|
||||
listRef.scrollToIndex(props.list.length - 1)
|
||||
|
||||
}
|
||||
|
||||
defineExpose({scrollToBottom})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<virtual-list class="virtual-list"
|
||||
:keeps="20"
|
||||
data-key="name"
|
||||
:data-sources="list"
|
||||
:estimate-size="85"
|
||||
ref="listRef"
|
||||
>
|
||||
<template #={source,index}>
|
||||
<div class="common-list-item space15"
|
||||
:class="{active:activeIndex === index}"
|
||||
@click="emit('change',{word:source,index})"
|
||||
>
|
||||
<div class="left">
|
||||
<div class="title-wrapper">
|
||||
<div class="item-title">
|
||||
<span class="word" :class="!showWord && 'text-shadow'">{{ source.name }}</span>
|
||||
<span class="phonetic">{{ source.usphone }}</span>
|
||||
<VolumeIcon class="volume" @click="playWordAudio(source.name)"></VolumeIcon>
|
||||
</div>
|
||||
<div class="item-sub-title" v-if="source.trans.length && showTranslate">
|
||||
<div v-for="item in source.trans">{{ item }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<slot :word="source" :index="index"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</virtual-list>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/variable";
|
||||
|
||||
.virtual-list {
|
||||
overflow: overlay;
|
||||
height: 100%;
|
||||
padding: 0 var(--space);
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
@@ -1,121 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import {Word} from "../../types.ts";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
import {watch} from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
list: Word[],
|
||||
activeIndex?: number,
|
||||
isActive?: boolean
|
||||
showTranslate?: boolean
|
||||
showWord?: boolean
|
||||
}>(), {
|
||||
activeIndex: -1,
|
||||
isActive: false,
|
||||
showTranslate: true,
|
||||
showWord: true
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
click: [val: { word: Word, index: number }],
|
||||
}>()
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
const listRef: any = $ref()
|
||||
|
||||
function scrollViewToCenter(index: number) {
|
||||
if (index === -1) return
|
||||
listRef.scrollToIndex(index)
|
||||
// listRef.children[index]?.scrollIntoView({block: 'center', behavior: 'smooth'})
|
||||
}
|
||||
|
||||
watch(() => props.activeIndex, (n: any) => {
|
||||
if (settingStore.showPanel) {
|
||||
scrollViewToCenter(n)
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => props.isActive, (n: boolean) => {
|
||||
setTimeout(() => {
|
||||
if (n) scrollViewToCenter(props.activeIndex)
|
||||
}, 300)
|
||||
})
|
||||
|
||||
// watch(() => props.list, () => {
|
||||
// listRef.scrollTo(0, 0)
|
||||
// })
|
||||
|
||||
const playWordAudio = usePlayWordAudio()
|
||||
|
||||
function reset() {
|
||||
listRef.reset()
|
||||
}
|
||||
|
||||
function scrollToBottom() {
|
||||
listRef.scrollToBottom()
|
||||
}
|
||||
|
||||
function scrollToItem(index: number) {
|
||||
listRef.scrollToItem(index)
|
||||
}
|
||||
|
||||
defineExpose({scrollToBottom, scrollToItem})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DynamicScroller
|
||||
:items="list"
|
||||
ref="listRef"
|
||||
:min-item-size="90"
|
||||
class="scroller"
|
||||
>
|
||||
<template v-slot="{ item, index, active }">
|
||||
<DynamicScrollerItem
|
||||
:item="item"
|
||||
:active="active"
|
||||
:size-dependencies="[
|
||||
item.id,
|
||||
]"
|
||||
:data-index="index"
|
||||
>
|
||||
<div class="list-item-wrapper">
|
||||
<div class="common-list-item"
|
||||
:class="{active:activeIndex === index}"
|
||||
@click="emit('click',{word:item,index})"
|
||||
>
|
||||
<div class="left">
|
||||
<slot name="prefix" :word="item" :index="index"></slot>
|
||||
<div class="title-wrapper">
|
||||
<div class="item-title">
|
||||
<span class="word" :class="!showWord && 'text-shadow'">{{ item.name }}</span>
|
||||
<span class="phonetic">{{ item.usphone }}</span>
|
||||
<VolumeIcon class="volume" @click="playWordAudio(item.name)"></VolumeIcon>
|
||||
</div>
|
||||
<div class="item-sub-title" v-if="item.trans.length && showTranslate">
|
||||
<div v-for="tran in item.trans">{{ tran }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<slot :word="item" :index="index"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DynamicScrollerItem>
|
||||
</template>
|
||||
</DynamicScroller>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/variable";
|
||||
|
||||
.scroller {
|
||||
height: 100%;
|
||||
padding: 0 var(--space);
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
@@ -1,11 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -2,11 +2,7 @@
|
||||
|
||||
import Input from "@/components/Input.vue";
|
||||
import {$computed, $ref} from "vue/macros";
|
||||
import {Article, Word} from "@/types.ts";
|
||||
import ListItem from "@/components/list/ListItem.vue";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {onMounted, useAttrs, watch} from "vue";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {Article} from "@/types.ts";
|
||||
import BaseList from "@/components/list2/BaseList.vue";
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
|
||||
@@ -76,6 +76,11 @@ onMounted(() => {
|
||||
})
|
||||
}, 300)
|
||||
break
|
||||
case 'detail':
|
||||
setTimeout(() => {
|
||||
selectDict({dict: runtimeStore.editDict})
|
||||
}, 300)
|
||||
break
|
||||
case 'editDict':
|
||||
setTimeout(() => {
|
||||
selectDict({dict: runtimeStore.editDict}, () => {
|
||||
@@ -97,12 +102,10 @@ onMounted(() => {
|
||||
step = 0
|
||||
}
|
||||
if (type === "collect") {
|
||||
selectDict({dict: store.collect, index: 0})
|
||||
// addWord('residue')
|
||||
selectDict({dict: store.collect})
|
||||
}
|
||||
if (type === "simple") {
|
||||
selectDict({dict: store.simple, index: 0})
|
||||
// addWord('residue')
|
||||
selectDict({dict: store.simple})
|
||||
}
|
||||
})
|
||||
// console.log('categoryList', categoryList)
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import {Word} from "@/types.ts";
|
||||
|
||||
const props = defineProps<{
|
||||
items: Word[]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DynamicScroller
|
||||
:items="items"
|
||||
:min-item-size="54"
|
||||
class="scroller"
|
||||
>
|
||||
<template v-slot="{ item, index, active }">
|
||||
<DynamicScrollerItem
|
||||
:item="item"
|
||||
:active="active"
|
||||
:size-dependencies="[
|
||||
item.name,
|
||||
]"
|
||||
:data-index="index"
|
||||
>
|
||||
|
||||
<div class="text">{{ item.name }}</div>
|
||||
</DynamicScrollerItem>
|
||||
</template>
|
||||
</DynamicScroller>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.scroller {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -4,7 +4,6 @@ import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import Empty from "@/components/Empty.vue";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import ArticleList3 from "@/components/list/ArticleList3.vue";
|
||||
import {$computed, $ref} from "vue/macros";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {Article, DefaultArticle, DefaultDict, Dict, DictResource, DictType, Sort, TranslateType} from "@/types.ts";
|
||||
@@ -95,9 +94,10 @@ async function getDictDetail(val: {
|
||||
s.id = nanoid(6)
|
||||
})
|
||||
runtimeStore.editDict.articles = cloneDeep(v)
|
||||
} else {
|
||||
runtimeStore.editDict.length = runtimeStore.editDict.articles.length
|
||||
}
|
||||
}
|
||||
runtimeStore.editDict.length = runtimeStore.editDict.articles.length + runtimeStore.editDict
|
||||
loading = false
|
||||
}
|
||||
|
||||
@@ -322,12 +322,12 @@ defineExpose({getDictDetail, add, editDict})
|
||||
</template>
|
||||
<template v-slot:suffix="{item,index}">
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
class="del"
|
||||
@click="emitter.emit(EventKey.openArticleListModal,item)"
|
||||
title="编辑"
|
||||
icon="tabler:edit"/>
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
class="del"
|
||||
@click="delArticle(index)"
|
||||
title="删除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {Sort, Word} from "@/types.ts";
|
||||
import VirtualWordList2 from "@/components/list/VirtualWordList2.vue";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import Empty from "@/components/Empty.vue";
|
||||
import {$computed, $ref} from "vue/macros";
|
||||
@@ -10,9 +9,8 @@ import MiniDialog from "@/components/dialog/MiniDialog.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {useWindowClick} from "@/hooks/event.ts";
|
||||
import {reverse, shuffle} from "lodash-es";
|
||||
import BaseList from "@/components/list2/BaseList.vue";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
import WordList from '@/components/list2/WordList.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
title: string,
|
||||
@@ -24,8 +22,8 @@ const props = defineProps<{
|
||||
|
||||
const emit = defineEmits<{
|
||||
add: []
|
||||
edit: [val: { word: Word, index: number }]
|
||||
del: [val: { word: Word, index: number }],
|
||||
edit: [val: { item: Word, index: number }]
|
||||
del: [val: { item: Word, index: number }],
|
||||
'update:list': [val: Word[]]
|
||||
}>()
|
||||
|
||||
@@ -61,7 +59,7 @@ let checkedTotal = $computed(() => {
|
||||
return props.list.filter(v => v.checked).length
|
||||
})
|
||||
|
||||
function del(val: { word: Word, index: number }) {
|
||||
function del(val: { item: Word, index: number }) {
|
||||
props.list.splice(val.index, 1)
|
||||
emit('del', val)
|
||||
}
|
||||
@@ -144,8 +142,7 @@ const playWordAudio = usePlayWordAudio()
|
||||
</div>
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<!-- TODO -->
|
||||
<BaseList
|
||||
<WordList
|
||||
ref="listRef"
|
||||
:list="list"
|
||||
v-if="list.length"
|
||||
@@ -156,29 +153,19 @@ const playWordAudio = usePlayWordAudio()
|
||||
@change="handleCheckedChange({item})"
|
||||
size="large"/>
|
||||
</template>
|
||||
<template v-slot="{item,index}">
|
||||
<div class="item-title">
|
||||
<span class="word">{{ item.name }}</span>
|
||||
<span class="phonetic">{{ item.usphone }}</span>
|
||||
<VolumeIcon class="volume" @click="playWordAudio(item.name)"></VolumeIcon>
|
||||
</div>
|
||||
<div class="item-sub-title" v-if="item.trans.length">
|
||||
<div v-for="tran in item.trans">{{ tran }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:suffix="{item,index}" v-if="canOperation">
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
class="del"
|
||||
@click="emit('edit',{item,index})"
|
||||
title="编辑"
|
||||
icon="tabler:edit"/>
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
class="del"
|
||||
@click="del({item,index})"
|
||||
title="删除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
</template>
|
||||
</BaseList>
|
||||
</WordList>
|
||||
<Empty :text="emptyTitle" v-else/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -604,7 +604,7 @@ defineExpose({getDictDetail, add: addWord, editDict})
|
||||
</template>
|
||||
<template v-slot:suffix="{ item, index }" v-if="isCanOperation">
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
class="del"
|
||||
@click="delWordChapter(item.id)"
|
||||
title="移除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
|
||||
@@ -29,26 +29,26 @@ const settingStore = useSettingStore()
|
||||
<div class="options">
|
||||
<BaseIcon
|
||||
v-if="!isSimple"
|
||||
class-name="collect"
|
||||
class="collect"
|
||||
@click="$emit('toggleSimple')"
|
||||
:title="`标记为简单词(快捷键:${settingStore.shortcutKeyMap[ShortcutKey.ToggleSimple]})`"
|
||||
icon="material-symbols:check-circle-outline-rounded"/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class-name="fill"
|
||||
class="fill"
|
||||
@click="$emit('toggleSimple')"
|
||||
:title="`取消标记简单词(快捷键:${settingStore.shortcutKeyMap[ShortcutKey.ToggleSimple]})`"
|
||||
icon="material-symbols:check-circle-rounded"/>
|
||||
|
||||
<BaseIcon
|
||||
v-if="!isCollect"
|
||||
class-name="collect"
|
||||
class="collect"
|
||||
@click="$emit('toggleCollect')"
|
||||
:title="`收藏(快捷键:${settingStore.shortcutKeyMap[ShortcutKey.ToggleCollect]})`"
|
||||
icon="ph:star"/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class-name="fill"
|
||||
class="fill"
|
||||
@click="$emit('toggleCollect')"
|
||||
:title="`取消收藏(快捷键:${settingStore.shortcutKeyMap[ShortcutKey.ToggleCollect]})`"
|
||||
icon="ph:star-fill"/>
|
||||
|
||||
@@ -13,14 +13,13 @@ import {useArticleOptions, useWordOptions} from "@/hooks/dict.ts";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import Tooltip from "@/components/Tooltip.vue";
|
||||
import IconWrapper from "@/components/IconWrapper.vue";
|
||||
import CommonWordList from "@/components/list/CommonWordList.vue";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
import ArticleList2 from "@/components/list/ArticleList2.vue";
|
||||
import {useRouter} from "vue-router";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import WordList from "@/components/list2/WordList.vue";
|
||||
import ArticleList4 from "@/components/list2/ArticleList4.vue";
|
||||
|
||||
const router = useRouter()
|
||||
const store = useBaseStore()
|
||||
@@ -133,7 +132,7 @@ function addSimple() {
|
||||
:list="store.collect.words">
|
||||
<template v-slot:suffix="{item,index}">
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
class="del"
|
||||
@click="toggleWordCollect(item)"
|
||||
title="移除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
@@ -142,19 +141,17 @@ function addSimple() {
|
||||
<Empty v-else/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<ArticleList2
|
||||
<ArticleList4
|
||||
v-if="store.collect.articles.length"
|
||||
:show-translate="true"
|
||||
v-model:list="store.collect.articles">
|
||||
<template v-slot="{source,index}">
|
||||
<template v-slot:suffix="{item,index}">
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
@click="toggleArticleCollect(source)"
|
||||
class="del"
|
||||
@click="toggleArticleCollect(item)"
|
||||
title="移除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
</template>
|
||||
</ArticleList2>
|
||||
|
||||
</ArticleList4>
|
||||
<Empty v-else/>
|
||||
</template>
|
||||
</div>
|
||||
@@ -185,7 +182,7 @@ function addSimple() {
|
||||
:list="store.simple.words">
|
||||
<template v-slot:suffix="{item,index}">
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
class="del"
|
||||
@click="delSimpleWord(item)"
|
||||
title="移除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
@@ -213,7 +210,7 @@ function addSimple() {
|
||||
:list="store.wrong.words">
|
||||
<template v-slot="{item,index}">
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
class="del"
|
||||
@click="delWrongWord(item)"
|
||||
title="移除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
|
||||
@@ -393,13 +393,13 @@ const {
|
||||
/>
|
||||
<BaseIcon
|
||||
v-if="!isArticleCollect(props.article)"
|
||||
class-name="collect"
|
||||
class="collect"
|
||||
@click="toggleArticleCollect(props.article)"
|
||||
:title="`收藏(快捷键:${settingStore.shortcutKeyMap[ShortcutKey.ToggleCollect]})`"
|
||||
icon="ph:star"/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class-name="fill"
|
||||
class="fill"
|
||||
@click="toggleArticleCollect(props.article)"
|
||||
:title="`取消收藏(快捷键:${settingStore.shortcutKeyMap[ShortcutKey.ToggleCollect]})`"
|
||||
icon="ph:star-fill"/>
|
||||
|
||||
@@ -17,11 +17,9 @@ import {Icon} from "@iconify/vue";
|
||||
import Tooltip from "@/components/Tooltip.vue";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import ArticleList2 from "@/components/list/ArticleList2.vue";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import {useArticleOptions} from "@/hooks/dict.ts";
|
||||
import ArticleList4 from "@/components/list2/ArticleList4.vue";
|
||||
import WordList from "@/components/list2/WordList.vue";
|
||||
|
||||
const store = useBaseStore()
|
||||
const practiceStore = usePracticeStore()
|
||||
@@ -290,12 +288,12 @@ const {
|
||||
<template v-slot:suffix="{item,index}">
|
||||
<BaseIcon
|
||||
v-if="!isArticleCollect(item)"
|
||||
class-name="collect"
|
||||
class="collect"
|
||||
@click="toggleArticleCollect(item)"
|
||||
title="收藏" icon="ph:star"/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class-name="fill"
|
||||
class="fill"
|
||||
@click="toggleArticleCollect(item)"
|
||||
title="取消收藏" icon="ph:star-fill"/>
|
||||
</template>
|
||||
|
||||
@@ -17,7 +17,6 @@ import IconWrapper from "@/components/IconWrapper.vue";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {useWordOptions} from "@/hooks/dict.ts";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import CommonWordList from "@/components/list/CommonWordList.vue";
|
||||
import WordList from "@/components/list2/WordList.vue";
|
||||
import Empty from "@/components/Empty.vue";
|
||||
|
||||
@@ -301,23 +300,23 @@ onUnmounted(() => {
|
||||
<template v-slot:suffix="{item,index}">
|
||||
<BaseIcon
|
||||
v-if="!isWordCollect(item)"
|
||||
class-name="collect"
|
||||
class="collect"
|
||||
@click="toggleWordCollect(item)"
|
||||
title="收藏" icon="ph:star"/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class-name="fill"
|
||||
class="fill"
|
||||
@click="toggleWordCollect(item)"
|
||||
title="取消收藏" icon="ph:star-fill"/>
|
||||
<BaseIcon
|
||||
v-if="!isWordSimple(item)"
|
||||
class-name="easy"
|
||||
class="easy"
|
||||
@click="toggleWordSimple(item)"
|
||||
title="标记为简单词"
|
||||
icon="material-symbols:check-circle-outline-rounded"/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class-name="fill"
|
||||
class="fill"
|
||||
@click="toggleWordSimple(item)"
|
||||
title="取消标记简单词"
|
||||
icon="material-symbols:check-circle-rounded"/>
|
||||
|
||||
Reference in New Issue
Block a user