From 352d30e80c056bc6d45c9eb7ca87d9943dfa8471 Mon Sep 17 00:00:00 2001 From: lingdocs <71590811+lingdocs@users.noreply.github.com> Date: Wed, 13 Apr 2022 16:07:35 +0500 Subject: [PATCH] smooth first stage --- package.json | 2 +- src/components/Keyframes.tsx | 35 ++++ src/components/vp-explorer/VPExplorerQuiz.tsx | 164 ++++++++++++------ src/components/vp-explorer/energy-drink.jpeg | Bin 0 -> 7003 bytes 4 files changed, 145 insertions(+), 56 deletions(-) create mode 100644 src/components/Keyframes.tsx create mode 100644 src/components/vp-explorer/energy-drink.jpeg diff --git a/package.json b/package.json index f131107..b119649 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lingdocs/pashto-inflector", - "version": "1.9.9", + "version": "2.0.0", "author": "lingdocs.com", "description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations", "homepage": "https://verbs.lingdocs.com", diff --git a/src/components/Keyframes.tsx b/src/components/Keyframes.tsx new file mode 100644 index 0000000..82dca98 --- /dev/null +++ b/src/components/Keyframes.tsx @@ -0,0 +1,35 @@ +import { CSSProperties } from "react"; + +interface IProps { + name: string; + [key: string]: CSSProperties | string; +} + +const Keyframes = (props: IProps) => { + const toCss = (cssObject: CSSProperties | string) => + typeof cssObject === "string" + ? cssObject + : Object.keys(cssObject).reduce((accumulator, key) => { + const cssKey = key.replace(/[A-Z]/g, v => `-${v.toLowerCase()}`); + const cssValue = (cssObject as any)[key].toString().replace("'", ""); + return `${accumulator}${cssKey}:${cssValue};`; + }, ""); + + return ( + + ); +}; + +export default Keyframes; \ No newline at end of file diff --git a/src/components/vp-explorer/VPExplorerQuiz.tsx b/src/components/vp-explorer/VPExplorerQuiz.tsx index f4429ed..c965619 100644 --- a/src/components/vp-explorer/VPExplorerQuiz.tsx +++ b/src/components/vp-explorer/VPExplorerQuiz.tsx @@ -10,6 +10,8 @@ import { getRandomTense } from "./TensePicker"; import { switchSubjObj } from "../../lib/phrase-building/vp-tools"; import playAudio from "../../lib/play-audio"; import TensePicker from "./TensePicker"; +import Keyframes from "../Keyframes"; +import energyDrink from "./energy-drink.jpeg"; const correctEmoji = ["✅", '🤓', "✅", '😊', "🌹", "✅", "✅", "🕺", "💃", '🥳', "👏", "✅", "💯", "😎", "✅", "👍"]; @@ -25,8 +27,12 @@ const answerFeedback: CSSProperties = { } const checkDuration = 400; +const stageLength = 7; type QuizState = { + stage: "multiple choice", + qNumber: number, + vps: T.VPSelectionComplete, answer: { ps: T.SingleOrLengthOpts; e?: string[] | undefined; @@ -40,16 +46,10 @@ function VPExplorerQuiz(props: { opts: T.TextOptions, vps: T.VPSelection, }) { - const startingQs = makeQuizState(props.vps); - const [vps, setVps] = useState(startingQs.VPS) - const [quizState, setQuizState] = useState(startingQs.qs); + const startingQs = tickQuizState(props.vps); + const [quizState, setQuizState] = useState(startingQs); const [showCheck, setShowCheck] = useState(false); const [currentCorrectEmoji, setCurrentCorrectEmoji] = useState(randFromArray(correctEmoji)); - function handleResetQuiz() { - const { VPS, qs } = makeQuizState(vps); - setVps(VPS); - setQuizState(qs); - } function checkQuizAnswer(a: T.PsString) { if (!quizState) return; if (isInAnswer(a, quizState.answer)) { @@ -57,7 +57,7 @@ function VPExplorerQuiz(props: { if (toPlay) playAudio(`correct-${randFromArray([1,2,3])}`); setShowCheck(true); setTimeout(() => { - handleResetQuiz(); + setQuizState(tickQuizState); }, checkDuration / 2); setTimeout(() => { setShowCheck(false); @@ -75,11 +75,15 @@ function VPExplorerQuiz(props: { }); } } - const rendered = renderVP(vps); + const rendered = renderVP(quizState.vps); const { subject, object } = rendered; const { e } = compileVP(rendered, { removeKing: false, shrinkServant: false }); - return
-
+ function handleRestart() { + setQuizState(tickQuizState(quizState.vps)); + } + return
+ +
Subject
{subject} @@ -90,44 +94,86 @@ function VPExplorerQuiz(props: {
}
null} mode={"quiz"} />
- {e &&
+ {e &&
{e.map(eLine =>
{eLine}
)}
}
{currentCorrectEmoji}
- {quizState.result === "waiting" ? <> -
Choose a correct answer:
- {quizState.options.map(o =>
-
{ - checkQuizAnswer(o); - }}> - {o} + {quizState.qNumber === stageLength ? +
+

👏 Congratulations

+

You finished the first level!

+

The other levels are still in development... In the meantime have an energy drink.

+
+ energy-dring
-
)} - :
-
❌ Wrong 😭
-
The correct answer was:
- - {quizState.options.find(x => isInAnswer(x, quizState.answer)) as T.PsString} - -
-
-
} + : (quizState.result === "waiting" + ? <> +
Choose a correct answer:
+ {quizState.options.map(o =>
+ +
)} + + :
+
❌ Wrong 😭
+
The correct answer was:
+ + {quizState.options.find(x => isInAnswer(x, quizState.answer)) as T.PsString} + +
+ +
+
) + } +
; } +function ProgressBar({ quizState }: { quizState: QuizState }) { + function getProgressWidth(): string { + const num = getPercentageDone({ current: quizState.qNumber, total: stageLength }); + return `${num}%`; + } + return
+
+
+ +
+
+ Level 1: Multiple Choice +
+
; +} + +function getPercentageDone(progress: { current: number, total: number }): number { + return Math.round( + (progress.current / (progress.total + 1)) * 100 + ); +} + function QuizNPDisplay({ children }: { children: T.Rendered | T.Person.ThirdPlurMale }) { return
{(typeof children === "number") @@ -136,14 +182,21 @@ function QuizNPDisplay({ children }: { children: T.Rendered | T.P
; } - -function makeQuizState(oldVps: T.VPSelection): { VPS: T.VPSelectionComplete, qs: QuizState } { +/** + * creates a fresh QuizState when a VPSelection is passed + * advances a QuizState when a QuizState is passed + * + * @param startingWith + * @returns + */ +function tickQuizState(startingWith: T.VPSelection | QuizState): QuizState { function makeRes(x: T.VPSelectionComplete) { return compileVP(renderVP(x), { removeKing: false, shrinkServant: false }); } + const oldVps = "stage" in startingWith ? startingWith.vps : startingWith; // for now, always inforce positive - const vps = getRandomVPSelection("both")({ ...oldVps, verb: { ...oldVps.verb, negative: false }}); - const wrongStates: T.VPSelectionComplete[] = []; + const newVps = getRandomVPSelection("both")({ ...oldVps, verb: { ...oldVps.verb, negative: false }}); + const wrongVpsS: T.VPSelectionComplete[] = []; // don't do the SO switches every time const wholeTimeSOSwitch = randFromArray([true, false]); [1, 2, 3].forEach(() => { @@ -152,23 +205,24 @@ function makeQuizState(oldVps: T.VPSelection): { VPS: T.VPSelectionComplete, qs: const SOSwitch = wholeTimeSOSwitch && randFromArray([true, false]); // TODO: if switich subj and obj, include the tense being correct maybe v = getRandomVPSelection("tenses")( - SOSwitch ? switchSubjObj(vps) : vps, + SOSwitch ? switchSubjObj(newVps) : newVps, ); // eslint-disable-next-line - } while (wrongStates.find(x => x.verb.tense === v.verb.tense)); - wrongStates.push(v); + } while (wrongVpsS.find(x => x.verb.tense === v.verb.tense)); + wrongVpsS.push(v); }); - const answer = makeRes(vps); - const wrongAnswers = wrongStates.map(makeRes); + const answer = makeRes(newVps); + const wrongAnswers = wrongVpsS.map(makeRes); const allAnswers = shuffleArray([...wrongAnswers, answer]); const options = allAnswers.map(getOptionFromResult); + const qNumber = ("stage" in startingWith) ? (startingWith.qNumber + 1) : 0; return { - VPS: vps, - qs: { - answer, - options, - result: "waiting", - }, + stage: "multiple choice", + qNumber, + vps: newVps, + answer, + options, + result: "waiting", }; } @@ -224,8 +278,14 @@ function getRandomVPSelection(mix: MixType = "both") { distance: "far", person: obj, }; - const s = randSubj; // ensure that the verb selection is complete + if (mix === "tenses") { + return { + subject: subject !== undefined ? subject : randSubj, + // @ts-ignore + verb: randomizeTense(verb, true), + } + } const v: T.VerbSelectionComplete = { ...verb, object: ( @@ -236,14 +296,8 @@ function getRandomVPSelection(mix: MixType = "both") { ? randObj : verb.object, }; - if (mix === "tenses") { - return { - subject: subject !== undefined ? subject : randSubj, - verb: randomizeTense(v, true), - } - } return { - subject: s, + subject: randSubj, verb: randomizeTense(v, true), }; }; diff --git a/src/components/vp-explorer/energy-drink.jpeg b/src/components/vp-explorer/energy-drink.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..36df01e1cac0fcfdab9a76200548597eb525149b GIT binary patch literal 7003 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 literal 0 HcmV?d00001