diff --git a/package.json b/package.json index 73f2ae7..d71d242 100644 --- a/package.json +++ b/package.json @@ -18,12 +18,14 @@ "lodash": "^4.17.21", "pinia": "^2.1.4", "pinyin-pro": "^3.15.4", + "vite-svg-loader": "^5.1.0", "vue": "^3.3.4", "vue-router": "^4.2.2" }, "devDependencies": { "@rushstack/eslint-patch": "^1.2.0", "@tsconfig/node18": "^2.0.1", + "@types/lodash": "^4.14.202", "@types/node": "^18.16.17", "@vitejs/plugin-vue": "^4.2.3", "@vitejs/plugin-vue-jsx": "^3.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0e0f751..97d0837 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,6 +3,7 @@ lockfileVersion: 5.4 specifiers: '@rushstack/eslint-patch': ^1.2.0 '@tsconfig/node18': ^2.0.1 + '@types/lodash': ^4.14.202 '@types/node': ^18.16.17 '@vitejs/plugin-vue': ^4.2.3 '@vitejs/plugin-vue-jsx': ^3.0.1 @@ -22,6 +23,7 @@ specifiers: sass: ^1.63.6 typescript: ~5.0.4 vite: ^4.3.9 + vite-svg-loader: ^5.1.0 vue: ^3.3.4 vue-router: ^4.2.2 vue-tsc: ^1.6.5 @@ -33,12 +35,14 @@ dependencies: lodash: 4.17.21 pinia: 2.1.4_typescript@5.0.4+vue@3.3.4 pinyin-pro: 3.15.4 + vite-svg-loader: 5.1.0_vue@3.3.4 vue: 3.3.4 vue-router: 4.2.2_vue@3.3.4 devDependencies: '@rushstack/eslint-patch': 1.3.2 '@tsconfig/node18': 2.0.1 + '@types/lodash': 4.14.202 '@types/node': 18.16.18 '@vitejs/plugin-vue': 4.2.3_vite@4.3.9+vue@3.3.4 '@vitejs/plugin-vue-jsx': 3.0.1_vite@4.3.9+vue@3.3.4 @@ -670,6 +674,11 @@ packages: resolution: {integrity: sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==} dev: true + /@trysound/sax/0.2.0: + resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} + engines: {node: '>=10.13.0'} + dev: false + /@tsconfig/node18/2.0.1: resolution: {integrity: sha512-UqdfvuJK0SArA2CxhKWwwAWfnVSXiYe63bVpMutc27vpngCntGUZQETO24pEJ46zU6XM+7SpqYoMgcO3bM11Ew==} dev: true @@ -678,6 +687,10 @@ packages: resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} dev: true + /@types/lodash/4.14.202: + resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==} + dev: true + /@types/node/18.16.18: resolution: {integrity: sha512-/aNaQZD0+iSBAGnvvN2Cx92HqE5sZCPZtx2TsK+4nvV23fFe09jVDvpArXr2j9DnYlzuU9WuoykDDc6wqvpNcw==} dev: true @@ -1149,7 +1162,6 @@ packages: /boolbase/1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - dev: true /brace-expansion/1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -1263,6 +1275,11 @@ packages: delayed-stream: 1.0.0 dev: false + /commander/7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + dev: false + /concat-map/0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true @@ -1291,12 +1308,50 @@ packages: which: 2.0.2 dev: true + /css-select/5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.1.0 + nth-check: 2.1.1 + dev: false + + /css-tree/2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.0.2 + dev: false + + /css-tree/2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.0.2 + dev: false + + /css-what/6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + dev: false + /cssesc/3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true dev: true + /csso/5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + dependencies: + css-tree: 2.2.1 + dev: false + /csstype/3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} @@ -1347,10 +1402,42 @@ packages: esutils: 2.0.3 dev: true + /dom-serializer/2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + dev: false + + /domelementtype/2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: false + + /domhandler/5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: false + + /domutils/3.1.0: + resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: false + /electron-to-chromium/1.4.436: resolution: {integrity: sha512-aktOxo8fnrMC8vOIBMVS3PXbT1nrPQ+SouUuN7Y0a+Rw3pOMrvIV92Ybnax7x4tugA+ZpYA5fOHTby7ama8OQQ==} dev: true + /entities/4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: false + /error-ex/1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: @@ -2157,6 +2244,14 @@ packages: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 + /mdn-data/2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + dev: false + + /mdn-data/2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + dev: false + /memorystream/0.3.1: resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} engines: {node: '>= 0.10.0'} @@ -2263,7 +2358,6 @@ packages: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} dependencies: boolbase: 1.0.0 - dev: true /object-inspect/1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} @@ -2697,6 +2791,20 @@ packages: resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} dev: true + /svgo/3.1.0: + resolution: {integrity: sha512-R5SnNA89w1dYgNv570591F66v34b3eQShpIBcQtZtM5trJwm1VvxbIoMpRYY3ybTAutcKTLEmTsdnaknOHbiQA==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + '@trysound/sax': 0.2.0 + commander: 7.2.0 + css-select: 5.1.0 + css-tree: 2.3.1 + css-what: 6.1.0 + csso: 5.0.5 + picocolors: 1.0.0 + dev: false + /text-table/0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -2788,6 +2896,15 @@ packages: spdx-expression-parse: 3.0.1 dev: true + /vite-svg-loader/5.1.0_vue@3.3.4: + resolution: {integrity: sha512-M/wqwtOEjgb956/+m5ZrYT/Iq6Hax0OakWbokj8+9PXOnB7b/4AxESHieEtnNEy7ZpjsjYW1/5nK8fATQMmRxw==} + peerDependencies: + vue: '>=3.2.13' + dependencies: + svgo: 3.1.0 + vue: 3.3.4 + dev: false + /vite/4.3.9_p77cnisglvxcw4xjyzbclrj6da: resolution: {integrity: sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==} engines: {node: ^14.18.0 || >=16.0.0} diff --git a/src/App.vue b/src/App.vue index 68ffd8f..14a82e3 100644 --- a/src/App.vue +++ b/src/App.vue @@ -90,6 +90,7 @@ const changeTheme = () => { 限时模式 词/成语模式 句子模式 + 自定义 键盘测试 diff --git a/src/assets/svg/change.svg b/src/assets/svg/change.svg new file mode 100644 index 0000000..25973d2 --- /dev/null +++ b/src/assets/svg/change.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/svg/setting.svg b/src/assets/svg/setting.svg new file mode 100644 index 0000000..984f786 --- /dev/null +++ b/src/assets/svg/setting.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/WordInput.vue b/src/components/WordInput.vue index b885853..13e0a18 100644 --- a/src/components/WordInput.vue +++ b/src/components/WordInput.vue @@ -19,11 +19,14 @@ const props = defineProps<{ quote: string; }>(); +const emit = defineEmits(['is-typing']); + const state = reactive({ currentAreaHeight: LINE_HEIGHT, isComposing: false, inputText: '', - quoteArr: [] as SentenceArrItem[] + quoteArr: [] as SentenceArrItem[], + isTyping: false }); onMounted(async () => { @@ -57,6 +60,12 @@ watch( watch( () => state.inputText, (newVal) => { + if (newVal === '') { + setTimeout(() => { + y.value = 0; + }); + } + const inputTextArr = newVal.split(''); state.quoteArr.forEach((item, index) => { item.isInput = false; @@ -73,16 +82,20 @@ watch( } ); +function focusInput() { + if (!inputAreaRef.value) return; + inputAreaRef.value.focus(); +} + function handlerInput(text: string) { state.inputText = text; const currentHeight = inputAreaRef.value?.offsetHeight; - console.log(currentHeight); if (currentHeight && currentHeight > Math.max(state.currentAreaHeight, LINE_HEIGHT * 2)) { y.value += LINE_HEIGHT; - } else if (currentHeight && currentHeight < Math.min(state.currentAreaHeight, LINE_HEIGHT * 2)) { + } else if (currentHeight && currentHeight < state.currentAreaHeight) { y.value -= LINE_HEIGHT; } - state.currentAreaHeight = currentHeight || 70; + state.currentAreaHeight = currentHeight || LINE_HEIGHT; } function pasteEvent(e: ClipboardEvent) { @@ -94,6 +107,7 @@ function keyDownEvent(e: KeyboardEvent) { } } function inputEvent(e: Event) { + emit('is-typing'); const input = e.target as HTMLElement; if (!state.isComposing) { handlerInput(input?.innerText); @@ -113,35 +127,82 @@ function compositionEndEvent(e: CompositionEvent) { handlerInput(text); } } + +defineExpose({ + focusInput +}); diff --git a/src/files/Sentence.json b/src/files/Quote.json similarity index 69% rename from src/files/Sentence.json rename to src/files/Quote.json index 05793fb..25f2d19 100644 --- a/src/files/Sentence.json +++ b/src/files/Quote.json @@ -13,6 +13,13 @@ "type": "散文", "length": "long", "content": "如果以一天中的时间来对应四季,当然春天是早晨,夏天是中午,秋天是黄昏,冬天是夜晚。如果以乐器来对应四季,我想春天应该是小号,夏天是定音鼓,秋天是大提琴,冬天是圆号和长笛。要是以这园子里的声响来对应四季呢?那么,春天是祭坛上空漂浮着的鸽子的哨音,夏天是冗长的蝉歌和杨树叶子哗啦啦地对蝉歌的取笑,秋天是古殿檐头的风铃响,冬天是啄木鸟随意而空旷的啄木声。以园中的景物对应四季,春天是一径时而苍白时而黑润的小路,时而明朗时而阴晦的天上摇荡着串串杨花;夏天是一条条耀眼而灼人的石凳,或阴凉而爬满了青苔的石阶,阶下有果皮,阶上有半张被坐皱的报纸;秋天是一座青铜的大钟,在园子的西北角上曾丢弃着一座很大的铜钟,铜钟与这园子一般年纪,浑身挂满绿锈,文字已不清晰;冬天,是林中空地上几只羽毛蓬松的老麻雀。以心绪对应四季呢?春天是卧病的季节,否则人们不易发觉春天的残忍与渴望;夏天,情人们应该在这个季节里失恋,不然就似乎对不起爱情;秋天是从外面买一棵盆花回家的时候,把花搁在阔别了的家中,并且打开窗户把阳光也放进屋里,慢慢回忆慢慢整理一些发过霉的东西;冬天伴着火炉和书,一遍遍坚定不死的决心,写一些并不发出的信。还可以用艺术形式对应四季,这样春天就是一幅画,夏天是一部长篇小说,秋天是一首短歌或诗,冬天是一群雕塑。以梦呢?以梦对应四季呢?春天是树尖上的呼喊,夏天是呼喊中的细雨,秋天是细雨中的土地,冬天是干净的土地上的一只孤零的烟斗。" + }, + { + "title": "冰灯", + "author": "佚名", + "type": "散文", + "length": "long", + "content": "冰灯是流行于中国北方的一种古老的民间艺术形式。因为独特的地域优势,黑龙江可以说是制作冰灯最早的地方。传说在很早以前,每到冬季的夜晚,在松嫩平原上,人们总会看到三五成群的农夫和渔民在悠然自得地喂马和捕鱼,他们所使用的照明工具就是用冰做成的灯笼。这便是最早的冰灯。当时制作冰灯的工艺也很简单,把水放进木桶里冻成冰坨,凿出空心,放个油灯在里面,用以照明,冰罩挡住了凛冽的寒风,黑夜里便有了不灭的灯盏,冰灯成了人们生活中不可缺少的帮手。后来,每逢新春佳节和上元之夜,人们又把它加以装饰,而成为供人观赏的独特的艺术表现形式。清代《黑龙江外纪》里对此有过详细的记载:“上元,城中张灯五夜,村落妇女来观剧者,车声彻夜不绝。有镂五六尺冰为寿星灯者,中燃双炬,望之如水晶人。”其时,冰灯在南方一些地方也相继出现过。乾隆、嘉庆年间,四川诗人张问陶曾写过一首专门描写冰灯的诗,题名就叫《冰灯》,诗云:“黑夜有炎凉,冰灯吐焰长。照来消热念,凿处漏寒光。影湿星沉水,神清月里霜。三冬足文史,底用探萤囊。”南京诗人金德荣在被谪戍新疆巴里坤时,在其古风长诗《巴里坤冰灯歌》中也咏叹道:“雪山高与天山接,上有万古不化雪。朔风一夜结作冰,裁雪妙手搏为冰。以矾入冰冰不化,以烛照冰光四射。五里之内尽通明,半月能教天不夜。元夕月轮照碧空,大千人入水晶宫......" } ], "medium": [ diff --git a/src/router/routes.ts b/src/router/routes.ts index a246d23..9fc0264 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -2,6 +2,7 @@ import TimeLimit from '@/view/TimeLimit.vue'; import WordsLimit from '@/view/WordsLimit.vue'; import QuoteLimit from '@/view/QuoteLimit.vue'; import TypingKeyboard from '@/view/TypingKeyboard.vue'; +import CustomPage from '@/view/CustomPage.vue'; import User from '@/view/User.vue'; export default [ @@ -9,5 +10,6 @@ export default [ { path: '/words', name: 'WordsLimit', component: WordsLimit }, { path: '/quote', name: 'QuoteLimit', component: QuoteLimit }, { path: '/keyboard', name: 'TypingKeyboard', component: TypingKeyboard }, + { path: '/custom', name: 'Custom', component: CustomPage }, { path: '/user/:id', name: 'User', component: User } ]; diff --git a/src/view/CustomPage.vue b/src/view/CustomPage.vue new file mode 100644 index 0000000..c4c7acf --- /dev/null +++ b/src/view/CustomPage.vue @@ -0,0 +1,13 @@ + + diff --git a/src/view/QuoteLimit.vue b/src/view/QuoteLimit.vue index 5d716e2..e1f54f4 100644 --- a/src/view/QuoteLimit.vue +++ b/src/view/QuoteLimit.vue @@ -1,5 +1,6 @@