This commit is contained in:
zyronon
2023-09-07 14:13:14 +08:00
parent 22bda84a7d
commit 7de7e053e7
10 changed files with 187 additions and 81 deletions

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8"/>
<link rel="icon" type="image/svg+xml" href="/vite.svg"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Vite + Vue + TS</title>
<title>Antd</title>
<script src='https://cdn.jsdelivr.net/npm/tesseract.js@4/dist/tesseract.min.js'></script>
<script>
+(function () {

View File

@@ -23,7 +23,6 @@
},
"devDependencies": {
"@iconify/json": "^2.2.102",
"@types/jquery": "^3.5.18",
"@types/lodash": "^4.14.196",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",

View File

@@ -2,6 +2,8 @@
import Toolbar from "@/components/Toolbar/Toolbar.vue"
import TypeArticle from "@/components/TypeArticle.vue"
</script>
<template>

View File

@@ -22,6 +22,7 @@ import Footer2 from "@/components/Footer2.vue"
import {Swiper, SwiperSlide} from "swiper/vue";
import 'swiper/css';
import {Swiper as SwiperClass} from "swiper/types";
import Type2 from "@/components/Type2.vue"
let article1 = `How does the older investor differ in his approach to investment from the younger investor?
There is no shortage of tipsters around offering 'get-rich-quick' opportunities. But if you are a serious private investor, leave the Las Vegas mentality to those with money to fritter. The serious investor needs a proper 'portfolio' -- a well-planned selection of investments, with a definite structure and a clear aim. But exactly how does a newcomer to the stock market go about achieving that?
@@ -46,7 +47,7 @@ Idealists have objected to the package tour, that the traveller abroad thereby d
Whether the remarkable growth of organized camping means the eventual death of the more independent kind is hard to say. Municipalities naturally want to secure the campers' site fees and other custom. Police are wary of itinerants who cannot be traced to a recognized camp boundary or to four walls. But most probably it will all depend upon campers themselves: how many heath fires they cause; how much litter they leave; in short, whether or not they wholly alienate landowners and those who live in the countryside. Only good scouting is likely to preserve the freedoms so dear to the heart of the eternal Boy Scout.
NIGEL BUXTON The Great Escape from The Weekend Telegraph`
article2 = `Economy is one powerful motive for camping? since after the initial outlay upon equipment, or through hiring it, the total expense can be far less than the cost of hotels. But, contrary to a popular assumption, it is far from being the only one, or even the greatest. The man who manoeuvres carelessly into his twenty pounds' worth of space at one of Europe's myriad permanent sites may find himself bumping a Bentley. More likely, Ford Escort will be hub to hub with Renault or Mercedes, but rarely with bicycles made for two.`
// article2 = `Economy is one powerful motive for camping? since after the initial outlay upon equipment, or through hiring it, the total expense can be far less than the cost of hotels. But, contrary to a popular assumption, it is far from being the only one, or even the greatest. The man who manoeuvres carelessly into his twenty pounds' worth of space at one of Europe's myriad permanent sites may find himself bumping a Bentley. More likely, Ford Escort will be hub to hub with Renault or Mercedes, but rarely with bicycles made for two.`
let isPlay = $ref(false)
let inputRef = $ref<HTMLInputElement>(null)
let articleWrapperRef = $ref<HTMLInputElement>(null)
@@ -376,12 +377,13 @@ function otherWord(word: string, i: number, i2: number, i3: number) {
<template>
<div class="type-wrapper">
<div class="content">
<div class="article-wrapper" ref="articleWrapperRef">
<article @click="focus">
<div class="section"
v-for="(section,indexI) in article.sections">
<div class="swiper-wrapper content">
<div class="swiper-list">
<div class="swiper-item">
<div class="article-wrapper" ref="articleWrapperRef">
<article @click="focus">
<div class="section"
v-for="(section,indexI) in article.sections">
<span class="sentence"
:class="[
sectionIndex === indexI && sentenceIndex === indexJ ?'isDictation':''
@@ -420,31 +422,38 @@ function otherWord(word: string, i: number, i2: number, i3: number) {
]">&nbsp;</span>
</span>
</span>
</div>
</article>
<div class="translate">
<div class="row"
:class="`translate${item.location}`"
v-for="item in article.translate">
<span class="space"></span>
<span class="text">{{ item.sentence }}</span>
</div>
</article>
<div class="translate">
<div class="row"
:class="`translate${item.location}`"
v-for="item in article.translate">
<span class="space"></span>
<span class="text">{{ item.sentence }}</span>
</div>
</div>
</div>
</div>
<div class="swiper-item">
<!-- <Type2-->
<!-- />-->
</div>
</div>
<input ref="inputRef"
class="inputEl"
type="text"
@keyup="onKeyUp"
@keydown="onKeyDown">
</div>
<Footer2
:total="statistics.total"
:startDate="statistics.startDate"
:inputNumber="statistics.inputNumber"
:wrongNumber="statistics.wrongNumber"
:correctRate="statistics.correctRate"
/>
<input ref="inputRef"
class="inputEl"
type="text"
@keyup="onKeyUp"
@keydown="onKeyDown">
</div>
<Footer2
:total="statistics.total"
:startDate="statistics.startDate"
:inputNumber="statistics.inputNumber"
:wrongNumber="statistics.wrongNumber"
:correctRate="statistics.correctRate"
/>
</template>
<style scoped lang="scss">
@@ -457,66 +466,69 @@ function otherWord(word: string, i: number, i2: number, i3: number) {
.type-wrapper {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
.content {
width: 60vw;
flex: 1;
overflow: auto;
width: 1000px;
position: relative;
}
article {
height: 100%;
font-size: 24rem;
line-height: 1.9;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
color: gray;
word-break: keep-all;
word-wrap: break-word;
white-space: pre-wrap;
padding-top: 20rem;
.article-wrapper {
article {
//height: 100%;
font-size: 24rem;
line-height: 1.9;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
color: gray;
word-break: keep-all;
word-wrap: break-word;
white-space: pre-wrap;
padding-top: 20rem;
.isDictation {
letter-spacing: 3rem;
}
.section {
margin-bottom: $space;
.sentence {
transition: all .3s;
.isDictation {
letter-spacing: 3rem;
}
.word {
display: inline-block;
.section {
margin-bottom: $space;
.sentence {
transition: all .3s;
}
.word {
display: inline-block;
}
}
}
}
.translate {
pointer-events: none;
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
font-size: 18rem;
color: gray;
line-height: 2.5;
letter-spacing: 3rem;
.row {
.translate {
pointer-events: none;
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
opacity: 0;
font-size: 18rem;
color: gray;
line-height: 2.5;
letter-spacing: 3rem;
display: none;
.space {
transition: all .3s;
display: inline-block;
.row {
position: absolute;
left: 0;
width: 100%;
opacity: 0;
.space {
transition: all .3s;
display: inline-block;
}
}
}
}
@@ -544,18 +556,29 @@ function otherWord(word: string, i: number, i2: number, i3: number) {
background: rgba(red, 0.6);
animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
}
}
.inputEl {
position: fixed;
//left: 100vw;
.inputEl {
position: fixed;
//left: 100vw;
}
.swiper-wrapper {
height: 100%;
width: 100%;
overflow: hidden;
.swiper-list {
transition: transform .3s;
//transform: translate3d(0, -100%, 0);
height: 200%;
.swiper-item {
height: 50%;
overflow: auto;
}
}
}
.swiper {
height: 100%;
width: 100%;
}
</style>

View File

@@ -231,7 +231,6 @@ async function onKeyDown(e: KeyboardEvent) {
.type-word {
display: flex;
//display: none;
align-items: center;
justify-content: center;
flex-direction: column;

View File

@@ -0,0 +1,51 @@
<script setup lang="ts">
import TypeWord from "@/components/TypeWord.vue"
import {onMounted} from "vue"
import {$ref} from "vue/macros"
import {watch} from "vue/dist/vue"
import Footer2 from "@/components/Footer2.vue"
let data = $ref({
index: -1,
words: [],
wrongWords: [],
originWrongWords: [],
repeatNumber: 0,
startDate: Date.now(),
correctRate: -1,
})
watch(data, () => {
if (data.index < 1) {
return data.correctRate = -1
}
if (data.wrongWords.length > data.index) {
return data.correctRate = 0
}
data.correctRate = 100 - Math.trunc((data.wrongWords.length / data.index) * 100)
})
onMounted(() => {
})
</script>
<template>
<TypeWord
v-model:data="data"
/>
<Footer2
:total="data.words.length"
:startDate="data.startDate"
:inputNumber="data.index"
:wrongNumber="data.wrongWords"
:correctRate="data.correctRate"
/>
</template>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,32 @@
import {defineStore} from "pinia"
import {Word} from "@/types.ts"
export interface PracticeState {
index: number,
words: Word[],
wrongWords: Word[],
originWrongWords: Word[],
repeatNumber: number,
startDate: number,
correctRate: number,
total: number,
inputNumber: number,
wrongNumber: number,
}
export const usePracticeStore = defineStore('practice', {
state: (): PracticeState => {
return {
index: -1,
words: [],
wrongWords: [],
originWrongWords: [],
repeatNumber: 0,
startDate: Date.now(),
correctRate: -1,
total: -1,
inputNumber: -1,
wrongNumber: -1,
}
}
})