diff --git a/package.json b/package.json
index df5a2c51..020fe2bc 100644
--- a/package.json
+++ b/package.json
@@ -21,11 +21,13 @@
"compromise": "^14.10.0",
"copy-to-clipboard": "^3.3.3",
"element-plus": "^2.3.9",
+ "file-saver": "^2.0.5",
"hover.css": "^2.3.2",
"localforage": "^1.10.0",
"lodash-es": "^4.17.21",
"mitt": "^3.0.1",
"pinia": "^2.1.6",
+ "sentence-splitter": "^4.2.1",
"swiper": "^10.1.0",
"tesseract.js": "^4.1.1",
"uuid": "^9.0.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 92de8dbe..9999ec05 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -26,6 +26,9 @@ dependencies:
element-plus:
specifier: ^2.3.9
version: 2.3.14(vue@3.3.4)
+ file-saver:
+ specifier: ^2.0.5
+ version: 2.0.5
hover.css:
specifier: ^2.3.2
version: 2.3.2
@@ -41,6 +44,9 @@ dependencies:
pinia:
specifier: ^2.1.6
version: 2.1.6(typescript@5.2.2)(vue@3.3.4)
+ sentence-splitter:
+ specifier: ^4.2.1
+ version: 4.2.1
swiper:
specifier: ^10.1.0
version: 10.3.0
@@ -819,6 +825,10 @@ packages:
resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==}
dev: false
+ /@textlint/ast-node-types@13.3.3:
+ resolution: {integrity: sha512-KCpJppfX3Km69twa6SmVEJ8mkyAZSrxw3XaaLQSlpc7PWnLUJSCHGPVECI1nSUDhiTd1r6zlRvWuyIAZJiov+A==}
+ dev: false
+
/@tsconfig/node10@1.0.9:
resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==}
requiresBuild: true
@@ -1201,6 +1211,10 @@ packages:
resolution: {integrity: sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==}
dev: false
+ /boundary@2.0.0:
+ resolution: {integrity: sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==}
+ dev: false
+
/brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
@@ -1700,6 +1714,10 @@ packages:
escape-string-regexp: 1.0.5
dev: true
+ /file-saver@2.0.5:
+ resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
+ dev: false
+
/fill-range@7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
@@ -2684,6 +2702,13 @@ packages:
lru-cache: 6.0.0
dev: true
+ /sentence-splitter@4.2.1:
+ resolution: {integrity: sha512-zn7awgCg40lyb+fe6N/fRJS3r+Ag3SmrmiYHZZSM9oQ2HTnwSMooUgQXSMLeQdi5HWMYOnhrovE2JZ3pyGU0dg==}
+ dependencies:
+ '@textlint/ast-node-types': 13.3.3
+ structured-source: 4.0.0
+ dev: false
+
/side-channel@1.0.4:
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
dependencies:
@@ -2743,6 +2768,12 @@ packages:
acorn: 8.10.0
dev: true
+ /structured-source@4.0.0:
+ resolution: {integrity: sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==}
+ dependencies:
+ boundary: 2.0.0
+ dev: false
+
/suffix-thumb@5.0.2:
resolution: {integrity: sha512-I5PWXAFKx3FYnI9a+dQMWNqTxoRt6vdBdb0O+BJ1sxXCWtSoQCusc13E58f+9p4MYx/qCnEMkD5jac6K2j3dgA==}
dev: false
diff --git a/src/assets/css/style.scss b/src/assets/css/style.scss
index bf809585..7317a8b2 100644
--- a/src/assets/css/style.scss
+++ b/src/assets/css/style.scss
@@ -99,6 +99,15 @@ a {
border-radius: 10rem;
}
+
+/* 火狐美化滚动条 */
+* {
+ scrollbar-color: $second #f3f4f9;
+ /* 滑块颜色 滚动条背景颜色 */
+ scrollbar-width: thin;
+ /* 滚动条宽度有三种:thin、auto、none */
+}
+
footer {
box-sizing: content-box;
height: $footer-height;
diff --git a/src/components/Add/AddArticle2.vue b/src/components/Add/AddArticle2.vue
index 1eb4c50f..d1f2fbab 100644
--- a/src/components/Add/AddArticle2.vue
+++ b/src/components/Add/AddArticle2.vue
@@ -1,5 +1,5 @@
@@ -298,8 +294,8 @@ function add() {
@@ -337,7 +333,7 @@ function add() {
标题:
本地翻译
网络翻译
@@ -490,6 +486,7 @@ function add() {
display: flex;
gap: $space;
padding: $space;
+ padding-top: 10rem;
//opacity: 0;
}
@@ -561,7 +558,7 @@ function add() {
.sentence {
margin-bottom: 20rem;
- &:last-child{
+ &:last-child {
margin-bottom: 0;
}
diff --git a/src/components/List.vue b/src/components/List.vue
index b9177e95..6c54a3c8 100644
--- a/src/components/List.vue
+++ b/src/components/List.vue
@@ -146,7 +146,7 @@ function delItem(item: T) {
.list-wrapper {
flex: 1;
- overflow: auto;
+ overflow: overlay;
padding-right: 5rem;
.search {
diff --git a/src/stores/base.ts b/src/stores/base.ts
index fdbcd87f..0415a0ab 100644
--- a/src/stores/base.ts
+++ b/src/stores/base.ts
@@ -5,258 +5,258 @@ import {emitter, EventKey} from "@/utils/eventBus.ts"
import {v4 as uuidv4} from 'uuid';
export interface State {
- newWordDict: Dict,
- skipWordDict: Dict,
- wrongWordDict: Dict,
- dict: Dict,
- myDicts: Dict[],
- current: {
- dictType: DictType,
- index: number,
- editIndex: number,
- repeatNumber: number,
- },
- simpleWords: string[],
- sideIsOpen: boolean,
- load: boolean
+ newWordDict: Dict,
+ skipWordDict: Dict,
+ wrongWordDict: Dict,
+ dict: Dict,
+ myDicts: Dict[],
+ current: {
+ dictType: DictType,
+ index: number,
+ editIndex: number,
+ repeatNumber: number,
+ },
+ simpleWords: string[],
+ sideIsOpen: boolean,
+ load: boolean
}
export const useBaseStore = defineStore('base', {
- state: (): State => {
- return {
- newWordDict: {
- name: '生词本',
- sort: Sort.normal,
- type: DictType.newDict,
- originWords: [],
- articles: [],
- words: [],
- chapterWordNumber: 15,
- chapterWords: [],
- chapterIndex: 0,
- chapterWordIndex: 0,
- statistics: [],
- url: '',
- },
- skipWordDict: {
- name: '简单词',
- sort: Sort.normal,
- type: DictType.skipDict,
- originWords: [],
- articles: [],
- words: [],
- chapterWordNumber: 15,
- chapterWords: [],
- chapterIndex: 0,
- chapterWordIndex: 0,
- statistics: [],
- url: '',
- },
- wrongWordDict: {
- name: '错词本',
- sort: Sort.normal,
- type: DictType.wrongDict,
- originWords: [],
- articles: [],
- words: [],
- chapterWordNumber: 15,
- chapterWords: [],
- chapterIndex: 0,
- chapterWordIndex: 0,
- statistics: [],
- url: '',
- },
- // dict: {
- // name: '新概念英语-2',
- // sort: Sort.normal,
- // type: DictType.innerDict,
- // originWords: [],
- // articles: [],
- // words: [],
- // chapterWordNumber: 15,
- // chapterWords: [],
- // chapterIndex: 0,
- // chapterWordIndex: 0,
- // statistics: [],
- // url: '/dicts/NCE_2.json',
- // },
- dict: {
- name: '新概念英语-2',
- sort: Sort.normal,
- type: DictType.publicArticle,
- originWords: [],
- articles: [],
- words: [],
- chapterWordNumber: 15,
- chapterWords: [],
- chapterIndex: 0,
- chapterWordIndex: 0,
- statistics: [],
- url: '/articles/NCE_2.json',
- },
- myDicts: [
- {
- name: '新概念英语-2',
- sort: Sort.normal,
- type: DictType.publicArticle,
- originWords: [],
- articles: [],
- words: [],
- chapterWordNumber: 15,
- chapterWords: [],
- chapterIndex: 0,
- chapterWordIndex: 0,
- statistics: [],
- url: '/articles/NCE_2.json',
- }
- ],
- current: {
- dictType: DictType.publicArticle,
- index: 0,
- editIndex: 0,
- repeatNumber: 0,
- },
- sideIsOpen: false,
- simpleWords: [
- 'a', 'an', 'of', 'and',
- 'i', 'my', 'you', 'your',
- 'me', 'am', 'is', 'do', 'are',
- 'what', 'who', 'where', 'how', 'no', 'yes',
- 'not', 'did', 'were', 'can', 'could', 'it',
- 'the', 'to'
- ],
- load: false
+ state: (): State => {
+ return {
+ newWordDict: {
+ name: '生词本',
+ sort: Sort.normal,
+ type: DictType.newDict,
+ originWords: [],
+ articles: [],
+ words: [],
+ chapterWordNumber: 15,
+ chapterWords: [],
+ chapterIndex: 0,
+ chapterWordIndex: 0,
+ statistics: [],
+ url: '',
+ },
+ skipWordDict: {
+ name: '简单词',
+ sort: Sort.normal,
+ type: DictType.skipDict,
+ originWords: [],
+ articles: [],
+ words: [],
+ chapterWordNumber: 15,
+ chapterWords: [],
+ chapterIndex: 0,
+ chapterWordIndex: 0,
+ statistics: [],
+ url: '',
+ },
+ wrongWordDict: {
+ name: '错词本',
+ sort: Sort.normal,
+ type: DictType.wrongDict,
+ originWords: [],
+ articles: [],
+ words: [],
+ chapterWordNumber: 15,
+ chapterWords: [],
+ chapterIndex: 0,
+ chapterWordIndex: 0,
+ statistics: [],
+ url: '',
+ },
+ // dict: {
+ // name: '新概念英语-2',
+ // sort: Sort.normal,
+ // type: DictType.innerDict,
+ // originWords: [],
+ // articles: [],
+ // words: [],
+ // chapterWordNumber: 15,
+ // chapterWords: [],
+ // chapterIndex: 0,
+ // chapterWordIndex: 0,
+ // statistics: [],
+ // url: '/dicts/NCE_2.json',
+ // },
+ dict: {
+ name: '新概念英语-2',
+ sort: Sort.normal,
+ type: DictType.publicArticle,
+ originWords: [],
+ articles: [],
+ words: [],
+ chapterWordNumber: 15,
+ chapterWords: [],
+ chapterIndex: 0,
+ chapterWordIndex: 0,
+ statistics: [],
+ url: '/articles/NCE_2.json',
+ },
+ myDicts: [
+ {
+ name: '新概念英语-2',
+ sort: Sort.normal,
+ type: DictType.publicArticle,
+ originWords: [],
+ articles: [],
+ words: [],
+ chapterWordNumber: 15,
+ chapterWords: [],
+ chapterIndex: 0,
+ chapterWordIndex: 0,
+ statistics: [],
+ url: '/articles/NCE_2.json',
}
+ ],
+ current: {
+ dictType: DictType.publicArticle,
+ index: 0,
+ editIndex: 0,
+ repeatNumber: 0,
+ },
+ sideIsOpen: false,
+ simpleWords: [
+ 'a', 'an', 'of', 'and',
+ 'i', 'my', 'you', 'your',
+ 'me', 'am', 'is', 'do', 'are',
+ 'what', 'who', 'where', 'how', 'no', 'yes',
+ 'not', 'did', 'were', 'can', 'could', 'it',
+ 'the', 'to'
+ ],
+ load: false
+ }
+ },
+ getters: {
+ skipWordNames: (state: State) => {
+ return state.skipWordDict.originWords.map(v => v.name.toLowerCase())
},
- getters: {
- skipWordNames: (state: State) => {
- return state.skipWordDict.originWords.map(v => v.name.toLowerCase())
- },
- skipWordNamesWithSimpleWords: (state: State) => {
- return state.skipWordDict.originWords.map(v => v.name.toLowerCase()).concat(state.simpleWords)
- },
- isArticle(state: State): boolean {
- return [
- DictType.publicArticle,
- DictType.customArticle
- ].includes(state.current.dictType)
- },
- currentDict(state: State): Dict {
- switch (state.current.dictType) {
- case DictType.newDict:
- return state.newWordDict
- case DictType.skipDict:
- return state.skipWordDict
- case DictType.wrongDict:
- return state.wrongWordDict
- case DictType.publicDict:
- case DictType.publicArticle:
- case DictType.customDict:
- case DictType.customArticle:
- return this.myDicts[this.current.index]
- }
- },
- currentEditDict(): Dict {
- return this.myDicts[this.current.editIndex]
- },
- wordIndex(state: State): number {
- return this.currentDict.wordIndex
- },
- chapter(state: State): Word[] {
- return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
- },
- //TODO 废弃
- word(state: State): Word {
- return {trans: [], name: '', usphone: '', ukphone: '',}
- },
- dictTitle(state: State) {
- let title = this.currentDict.name
- if ([DictType.publicDict, DictType.customDict].includes(this.current.dictType)) {
- title += ` 第${this.currentDict.chapterIndex + 1}章`
- }
- return title
+ skipWordNamesWithSimpleWords: (state: State) => {
+ return state.skipWordDict.originWords.map(v => v.name.toLowerCase()).concat(state.simpleWords)
+ },
+ isArticle(state: State): boolean {
+ return [
+ DictType.publicArticle,
+ DictType.customArticle
+ ].includes(state.current.dictType)
+ },
+ currentDict(state: State): Dict {
+ switch (state.current.dictType) {
+ case DictType.newDict:
+ return state.newWordDict
+ case DictType.skipDict:
+ return state.skipWordDict
+ case DictType.wrongDict:
+ return state.wrongWordDict
+ case DictType.publicDict:
+ case DictType.publicArticle:
+ case DictType.customDict:
+ case DictType.customArticle:
+ return this.myDicts[this.current.index]
+ }
+ },
+ currentEditDict(): Dict {
+ return this.myDicts[this.current.editIndex]
+ },
+ wordIndex(state: State): number {
+ return this.currentDict.wordIndex
+ },
+ chapter(state: State): Word[] {
+ return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
+ },
+ //TODO 废弃
+ word(state: State): Word {
+ return {trans: [], name: '', usphone: '', ukphone: '',}
+ },
+ dictTitle(state: State) {
+ let title = this.currentDict.name
+ if ([DictType.publicDict, DictType.customDict].includes(this.current.dictType)) {
+ title += ` 第${this.currentDict.chapterIndex + 1}章`
+ }
+ return title
+ }
+ },
+ actions: {
+ setState(obj: any) {
+ for (const [key, value] of Object.entries(obj)) {
+ this[key] = value
+ }
+ // console.log('this/', this)
+ },
+ async init() {
+ let configStr = localStorage.getItem(SaveDictKey)
+ if (configStr) {
+ let obj: State = JSON.parse(configStr)
+ // this.setState(obj)
+ }
+
+ if ([
+ DictType.newDict,
+ DictType.wrongDict,
+ DictType.skipDict,
+ ].includes(this.current.dictType)) {
+
+ } else {
+ if ([
+ DictType.publicDict,
+ DictType.customDict,
+ ].includes(this.current.dictType)) {
+ if (!this.currentDict.originWords.length) {
+ let r = await fetch(`${this.currentDict.url}`)
+ r.json().then(v => {
+ this.currentDict.originWords = cloneDeep(v)
+ this.currentDict.words = cloneDeep(v)
+ this.currentDict.chapterWords = chunk(this.dict.words, this.dict.chapterWordNumber)
+ this.load = true
+ })
+ }
}
- },
- actions: {
- setState(obj: any) {
- for (const [key, value] of Object.entries(obj)) {
- this[key] = value
- }
- // console.log('this/', this)
- },
- async init() {
- let configStr = localStorage.getItem(SaveDictKey)
- if (configStr) {
- let obj: State = JSON.parse(configStr)
- // this.setState(obj)
- }
- if ([
- DictType.newDict,
- DictType.wrongDict,
- DictType.skipDict,
- ].includes(this.current.dictType)) {
-
- } else {
- if ([
- DictType.publicDict,
- DictType.customDict,
- ].includes(this.current.dictType)) {
- if (!this.currentDict.originWords.length) {
- let r = await fetch(`${this.currentDict.url}`)
- r.json().then(v => {
- this.currentDict.originWords = cloneDeep(v)
- this.currentDict.words = cloneDeep(v)
- this.currentDict.chapterWords = chunk(this.dict.words, this.dict.chapterWordNumber)
- this.load = true
- })
- }
- }
-
- if ([
- DictType.publicArticle,
- DictType.customArticle,
- ].includes(this.current.dictType)) {
- if (!this.currentDict.articles.length) {
- let r = await fetch(`${this.currentDict.url}`)
- r.json().then((v: any[]) => {
- this.currentDict.articles = cloneDeep(v.map(v => {
- v.id = uuidv4()
- return v
- }))
- this.load = true
- })
- }
- }
- }
- },
- saveStatistics(statistics: Statistics) {
- if (statistics.spend > 1000 * 10) {
- this.currentDict.statistics.push(statistics)
- }
- },
- async changeDict(dict: Dict, chapterIndex: number = dict.chapterIndex, chapterWordIndex: number = dict.chapterWordNumber) {
- this.saveStatistics()
- console.log('changeDict', cloneDeep(dict), chapterIndex, chapterWordIndex)
- this.current.dictType = dict.type
- if ([DictType.newDict,
- DictType.skipDict,
- DictType.wrongDict].includes(dict.type)) {
- this[dict.type].chapterIndex = chapterIndex
- this[dict.type].chapterWordIndex = chapterWordIndex
- } else {
- this.dict = cloneDeep(dict)
- if (dict.originWords.length) {
- let r = await fetch(`/public/${this.dict.url}`)
- let v = await r.json()
- this.dict.originWords = cloneDeep(v)
- this.dict.words = cloneDeep(v)
- this.dict.chapters = chunk(this.dict.words, this.dict.chapterWordNumber)
- }
- this.dict.chapterIndex = chapterIndex
- this.dict.chapterWordIndex = chapterWordIndex
- }
- emitter.emit(EventKey.resetWord)
+ if ([
+ DictType.publicArticle,
+ DictType.customArticle,
+ ].includes(this.current.dictType)) {
+ if (!this.currentDict.articles.length) {
+ let r = await fetch(`${this.currentDict.url}`)
+ r.json().then((v: any[]) => {
+ this.currentDict.articles = cloneDeep(v.map(v => {
+ v.id = uuidv4()
+ return v
+ }))
+ this.load = true
+ })
+ }
}
+ }
},
+ saveStatistics(statistics: Statistics) {
+ if (statistics.spend > 1000 * 10) {
+ this.currentDict.statistics.push(statistics)
+ }
+ },
+ async changeDict(dict: Dict, chapterIndex: number = dict.chapterIndex, chapterWordIndex: number = dict.chapterWordNumber) {
+ this.saveStatistics()
+ console.log('changeDict', cloneDeep(dict), chapterIndex, chapterWordIndex)
+ this.current.dictType = dict.type
+ if ([DictType.newDict,
+ DictType.skipDict,
+ DictType.wrongDict].includes(dict.type)) {
+ this[dict.type].chapterIndex = chapterIndex
+ this[dict.type].chapterWordIndex = chapterWordIndex
+ } else {
+ this.dict = cloneDeep(dict)
+ if (dict.originWords.length) {
+ let r = await fetch(`/public/${this.dict.url}`)
+ let v = await r.json()
+ this.dict.originWords = cloneDeep(v)
+ this.dict.words = cloneDeep(v)
+ this.dict.chapters = chunk(this.dict.words, this.dict.chapterWordNumber)
+ }
+ this.dict.chapterIndex = chapterIndex
+ this.dict.chapterWordIndex = chapterWordIndex
+ }
+ emitter.emit(EventKey.resetWord)
+ }
+ },
})
\ No newline at end of file