Skip to content

Commit

Permalink
feat(client): switch input between word or sentence mode
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaodong2008 committed May 3, 2024
1 parent 826c781 commit 06ca458
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 32 deletions.
88 changes: 64 additions & 24 deletions apps/client/components/main/QuestionInput/QuestionInput.vue
Original file line number Diff line number Diff line change
@@ -1,38 +1,59 @@
<template>
<div class="text-center">
<div class="relative flex flex-wrap justify-center gap-2 transition-all">
<template
v-for="(w, i) in courseStore.words"
:key="i"
>
<template v-if="isShowWordNumber()">
<div
v-for="(word, index) in courseStore.words"
:key="index"
class="h-[4rem] rounded-[2px] border-b-2 border-solid text-[3em] leading-none transition-all"
:class="getWordsClassNames(i)"
:style="{ minWidth: `${inputWidth(w)}ch` }"
:class="getWordsClassNames(index)"
:style="{ minWidth: `${inputWidth(word)}ch` }"
>
{{ userInputWords[i]["userInput"] }}
{{ userInputWords[index]["userInput"] }}
</div>
<input
ref="inputEl"
class="absolute h-full w-full opacity-0"
type="text"
v-model="inputValue"
@keydown="handleKeydown"
@focus="focusInput"
@blur="blurInput"
@dblclick.prevent
@mousedown="preventCursorMove"
@compositionstart="handleCompositionStart"
@compositionend="handleCompositionEnd"
autoFocus
/>
</template>
<template v-else>
<div
:class="getSentenceClassNames()"
class="h-[4rem] rounded-[2px] border-b-2 border-solid px-8 text-[3em] leading-none transition-all"
>
{{ userInputWords.map((word) => word.userInput).join(" ") }}
</div>
<input
ref="inputEl"
class="absolute h-full w-full opacity-0"
type="text"
v-model="inputValue"
@keydown="handleKeydown"
@focus="focusInput"
@blur="blurInput"
@dblclick.prevent
@mousedown="preventCursorMove"
@compositionstart="handleCompositionStart"
@compositionend="handleCompositionEnd"
autoFocus
/>
</template>
<input
ref="inputEl"
class="absolute h-full w-full opacity-0"
type="text"
v-model="inputValue"
@keydown="handleKeydown"
@focus="focusInput"
@blur="blurInput"
@dblclick.prevent
@mousedown="preventCursorMove"
@compositionstart="handleCompositionStart"
@compositionend="handleCompositionEnd"
autoFocus
/>
</div>
</div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from "vue";
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
import { courseTimer } from "~/composables/courses/courseTimer";
import { useAnswerTip } from "~/composables/main/answerTip";
Expand All @@ -43,6 +64,7 @@ import { useAutoNextQuestion } from "~/composables/user/autoNext";
import { useErrorTip } from "~/composables/user/errorTip";
import { useKeyboardSound } from "~/composables/user/sound";
import { useSpaceSubmitAnswer } from "~/composables/user/submitKey";
import { useShowWordNumber } from "~/composables/user/wordNumber";
import { useShowWordsWidth } from "~/composables/user/words";
import { useCourseStore } from "~/store/course";
import { getWordWidth, useQuestionInput } from "./questionInputHelper";
Expand All @@ -55,6 +77,7 @@ const { inputEl, focusing, focusInput, blurInput, setInputCursorPosition, getInp
const { showAnswer } = useGameMode();
const { showSummary } = useSummary();
const { isShowWordsWidth } = useShowWordsWidth();
const { isShowWordNumber } = useShowWordNumber();
const { isUseSpaceSubmitAnswer } = useSpaceSubmitAnswer();
const { isKeyboardSoundEnabled } = useKeyboardSound();
const { checkPlayTypingSound, playTypingSound } = useTypingSound();
Expand All @@ -72,6 +95,10 @@ const { inputValue, userInputWords, submitAnswer, setInputValue, handleKeyboardI
});
const { showAnswerTip, hiddenAnswerTip } = useAnswerTip();
// only when isShowWordNumber is true
// determine window.focus compare to ref.inputEl
const isInputFocused = computed(() => document.activeElement === inputEl.value);
onMounted(() => {
focusInput();
resetCloseTip();
Expand Down Expand Up @@ -109,6 +136,18 @@ function focusInputWhenWIndowFocus() {
});
}
function getSentenceClassNames() {
const words = userInputWords;
let focus;
for (let i = 0; i < words.length; i++) {
const word = words[i];
if (word.isActive) focus = true;
if (word.incorrect) return "text-red-500 border-b-red-500";
}
if (focus) return "text-fuchsia-500 border-b-fuchsia-500";
return "text-[#20202099] border-b-gray-300 dark:text-gray-300 dark:border-b-gray-400";
}
function getWordsClassNames(index: number) {
const word = userInputWords[index];
// 当前单词激活 且 聚焦
Expand Down Expand Up @@ -202,11 +241,12 @@ function handleKeydown(e: KeyboardEvent) {
if (e.code === "Enter" && !isComposing.value) {
e.stopPropagation();
submitAnswer(handleAnswerRight, handleAnswerError);
console.log("submitAnswer:", userInputWords);
submitAnswer(isShowWordNumber(), handleAnswerRight, handleAnswerError);
return;
}
handleKeyboardInput(e, {
handleKeyboardInput(e, isShowWordNumber(), {
useSpaceSubmitAnswer: {
enable: isUseSpaceSubmitAnswer(),
rightCallback: handleAnswerRight,
Expand Down
29 changes: 21 additions & 8 deletions apps/client/composables/main/question.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,12 @@ export function useInput({
updateActiveWord(word.start);
}

function submitAnswer(correctCallback?: () => void, wrongCallback?: () => void) {
if (mode === Mode.Fix) return;
function submitAnswer(
showNumber: boolean,
correctCallback?: () => void,
wrongCallback?: () => void,
) {
if (showNumber && mode === Mode.Fix) return;
resetAllWordActive();
markIncorrectWord();

Expand Down Expand Up @@ -277,15 +281,19 @@ export function useInput({
};
}

function handleKeyboardInput(e: KeyboardEvent, options?: KeyboardInputOptions) {
function handleKeyboardInput(
e: KeyboardEvent,
showNumber: boolean,
options?: KeyboardInputOptions,
) {
// 禁止方向键移动
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.code)) {
e.preventDefault();
return;
}

// Fix_Input/Input 下启用空格提交 且 在最后一个单词位置
if (mode !== Mode.Fix && e.code === "Space" && lastWordIsActive()) {
if (showNumber && mode !== Mode.Fix && e.code === "Space" && lastWordIsActive()) {
e.preventDefault();
e.stopPropagation(); // 阻止事件冒泡
handleSpaceSubmitAnswer(options?.useSpaceSubmitAnswer);
Expand All @@ -294,7 +302,7 @@ export function useInput({

// Fix 模式下 允许用户按下任意键去修改第一个错误的单词
// 并且按下的这个键直接上屏
if (mode === Mode.Fix) {
if (showNumber && mode === Mode.Fix) {
if (e.code === "Space" || e.code === "Backspace") {
e.preventDefault();
}
Expand All @@ -304,15 +312,20 @@ export function useInput({
}

// Fix_Input 下启用空格提交 且 在最后一个错误单词位置
if (mode === Mode.Fix_Input && e.code === "Space" && isLastIncorrectWord()) {
if (showNumber && mode === Mode.Fix_Input && e.code === "Space" && isLastIncorrectWord()) {
e.preventDefault();
e.stopPropagation();
handleSpaceSubmitAnswer(options?.useSpaceSubmitAnswer);
return;
}

// Fix_Input 模式下当前编辑单词为空时,启用退格删除上一个错误单词
if (mode === Mode.Fix_Input && e.code === "Backspace" && isEmptyOfCurrentEditWord()) {
if (
showNumber &&
mode === Mode.Fix_Input &&
e.code === "Backspace" &&
isEmptyOfCurrentEditWord()
) {
e.preventDefault();
activePreviousIncorrectWord();
inputChangedCallback?.(e);
Expand All @@ -322,7 +335,7 @@ export function useInput({
// 空格修复单词
// Fix → 定位到第一个错误单词并清除
// Fix_Input → 定位到下一个错误单词并清除
if (mode !== Mode.Input && e.code === "Space") {
if (showNumber && mode !== Mode.Input && e.code === "Space") {
e.preventDefault();
fixIncorrectWord();
inputChangedCallback?.(e);
Expand Down

0 comments on commit 06ca458

Please sign in to comment.