From 35f29e80481adef536faa57e65c855d036f8f995 Mon Sep 17 00:00:00 2001 From: adueck Date: Fri, 6 Dec 2024 18:28:08 +0500 Subject: [PATCH] fix build --- package.json | 2 +- src/components/BasicVerbShowCase.tsx | 7 +- src/components/GenderTable.jsx | 4 +- src/components/InflectionCarousel.tsx | 106 +-- .../phrase-diagram/BlockDiagram.tsx | 60 +- .../phrase-diagram/EditableBlock.tsx | 157 ++-- src/content/verbs/GoingStems.tsx | 149 +++- src/games/sub-cores/EquativeGame.tsx | 369 +++++---- src/games/sub-cores/NPAdjGame.tsx | 306 ++++---- src/games/sub-cores/PerfectGame.tsx | 6 +- src/games/sub-cores/VerbFormulas.tsx | 732 ++++++++++-------- src/games/sub-cores/VerbGame.tsx | 6 +- yarn.lock | 8 +- 13 files changed, 1108 insertions(+), 804 deletions(-) diff --git a/package.json b/package.json index fedfc3f..0b1aa59 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "@formkit/auto-animate": "^1.0.0-beta.6", "@fortawesome/fontawesome-free": "5.15.4", "@lingdocs/lingdocs-main": "^0.3.3", - "@lingdocs/ps-react": "^7.7.3", + "@lingdocs/ps-react": "^7.7.4", "@mdx-js/rollup": "^2.2.1", "@stefanprobst/rehype-extract-toc": "^2.2.0", "@types/mdx": "^2.0.3", diff --git a/src/components/BasicVerbShowCase.tsx b/src/components/BasicVerbShowCase.tsx index 71e15e1..338bed2 100644 --- a/src/components/BasicVerbShowCase.tsx +++ b/src/components/BasicVerbShowCase.tsx @@ -49,12 +49,13 @@ function BasicVerbShowCase({ render={(item) => { return { title: ( - - {{ + + /> ), body: ( {item.ending &&
{typeof item.ending === "string" ? item.ending - : {item.ending}} + : }
}
- {item.ending ? "eg. " : ""}{item.ex} + {item.ending ? "eg. " : ""}
})} diff --git a/src/components/InflectionCarousel.tsx b/src/components/InflectionCarousel.tsx index 49cb0dd..3102c92 100644 --- a/src/components/InflectionCarousel.tsx +++ b/src/components/InflectionCarousel.tsx @@ -1,51 +1,67 @@ import Carousel from "./Carousel"; import { - InlinePs, - removeFVarients, - InflectionsTable, - inflectWord, - defaultTextOptions as opts, - getEnglishWord, - Types as T, + InlinePs, + removeFVarients, + InflectionsTable, + inflectWord, + defaultTextOptions as opts, + getEnglishWord, + Types as T, } from "@lingdocs/ps-react"; -function InflectionCarousel({ items }: { items: (T.NounEntry | T.AdjectiveEntry)[] }) { - if (!items.length) { - return "no items for carousel"; - } - return ( -
- { - const e = getEnglishWord(item); - const english = e === undefined - ? item.e - : typeof e === "string" - ? e - : e.singular !== undefined - ? e.singular - : item.e; - const infOut = inflectWord(item); - if (!infOut || !infOut.inflections) { - return { - title: "Oops! 🤷‍♂️", - // @ts-ignore - body:
Oops! No inflections for {item}
, - }; - } - return { - // @ts-ignore - title: , - body: , - }; - }}/> -
- ); +function InflectionCarousel({ + items, +}: { + items: (T.NounEntry | T.AdjectiveEntry)[]; +}) { + if (!items.length) { + return "no items for carousel"; + } + return ( +
+ { + const e = getEnglishWord(item); + const english = + e === undefined + ? item.e + : typeof e === "string" + ? e + : e.singular !== undefined + ? e.singular + : item.e; + const infOut = inflectWord(item); + if (!infOut || !infOut.inflections) { + return { + title: "Oops! 🤷‍♂️", + // @ts-ignore + body: ( +
+ Oops! No inflections for +
+ ), + }; + } + return { + // @ts-ignore + title: ( + + ), + body: ( + + ), + }; + }} + /> +
+ ); } -export default InflectionCarousel; \ No newline at end of file +export default InflectionCarousel; diff --git a/src/components/phrase-diagram/BlockDiagram.tsx b/src/components/phrase-diagram/BlockDiagram.tsx index 2e54815..ed9a65f 100644 --- a/src/components/phrase-diagram/BlockDiagram.tsx +++ b/src/components/phrase-diagram/BlockDiagram.tsx @@ -1,33 +1,47 @@ import { - renderNPSelection, - Types as T, - renderAPSelection, - NPBlock, - APBlock, - getEnglishFromRendered, + renderNPSelection, + Types as T, + renderAPSelection, + NPBlock, + APBlock, + getEnglishFromRendered, } from "@lingdocs/ps-react"; -function BlockDiagram({ opts, children }: { - opts: T.TextOptions, - children: T.NPSelection | T.APSelection, +function BlockDiagram({ + opts, + children, +}: { + opts: T.TextOptions; + children: T.NPSelection | T.APSelection; }) { - try { - const rendered = children.type === "AP" + try { + const rendered = + children.type === "AP" ? renderAPSelection(children, 0) : renderNPSelection(children, false, false, "subject", "none", false); const english = getEnglishFromRendered(rendered); - return
-
- {rendered.type === "NP" - ? {rendered} - : {rendered}} + return ( +
+
+ {rendered.type === "NP" ? ( + + {rendered} + + ) : ( + + {rendered} + + )}
-
; - } catch(e) { - console.log(e); - return
ERROR
; - } +
+ ); + } catch (e) { + console.log(e); + return
ERROR
; + } } - -export default BlockDiagram; \ No newline at end of file +export default BlockDiagram; diff --git a/src/components/phrase-diagram/EditableBlock.tsx b/src/components/phrase-diagram/EditableBlock.tsx index 81c58fc..85776fe 100644 --- a/src/components/phrase-diagram/EditableBlock.tsx +++ b/src/components/phrase-diagram/EditableBlock.tsx @@ -1,88 +1,95 @@ -import { - Types as T, - NPPicker, - APPicker, -} from "@lingdocs/ps-react"; -import { - useEffect, - useRef, -} from "react"; +import { Types as T, NPPicker, APPicker } from "@lingdocs/ps-react"; +import { useEffect, useRef } from "react"; import { useState } from "react"; import BlockDiagram from "./BlockDiagram"; import entryFeeder from "../../lib/entry-feeder"; import autoAnimate from "@formkit/auto-animate"; export function EditIcon() { - return ; + return ; } -function selectionToBlock(s: T.NPSelection | T.APSelection): { type: "NP", block: T.NPSelection | undefined } | { type: "AP", block: T.APSelection | undefined } { - return (s.type === "AP") - ? { type: "AP", block: s } - : { type: "NP", block: s }; +function selectionToBlock( + s: T.NPSelection | T.APSelection +): + | { type: "NP"; block: T.NPSelection | undefined } + | { type: "AP"; block: T.APSelection | undefined } { + return s.type === "AP" ? { type: "AP", block: s } : { type: "NP", block: s }; } -function EditableBlock({ opts, children: block }: { - opts: T.TextOptions, - children: T.NPSelection | T.APSelection, +function EditableBlock({ + opts, + children: block, +}: { + opts: T.TextOptions; + children: T.NPSelection | T.APSelection; }) { - const parent = useRef(null); - useEffect(() => { - parent.current && autoAnimate(parent.current) - }, [parent]); - const [editing, setEditing] = useState(false); - const [edited, setEdited] = useState<{ - type: "NP", - block: T.NPSelection | undefined, - } | { - type: "AP", - block: T.APSelection | undefined, - }>(selectionToBlock(block)); - function handleNPChange(np: T.NPSelection | undefined) { - setEdited({ type: "NP", block: np }); - } - function handleAPChange(ap: T.APSelection | undefined) { - setEdited({ type: "AP", block: ap }); - } - function handleReset() { - setEdited(selectionToBlock(block)); - setEditing(false); - } - return
-
setEditing(true)} - > - {!editing ? : } -
-
- {editing &&
- {edited.type === "NP" - ? - : null} - /> - } -
} - {edited.block - && - {edited.block} - } -
-
; + const parent = useRef(null); + useEffect(() => { + parent.current && autoAnimate(parent.current); + }, [parent]); + const [editing, setEditing] = useState(false); + const [edited, setEdited] = useState< + | { + type: "NP"; + block: T.NPSelection | undefined; + } + | { + type: "AP"; + block: T.APSelection | undefined; + } + >(selectionToBlock(block)); + function handleNPChange(np: T.NPSelection | undefined) { + setEdited({ type: "NP", block: np }); + } + function handleAPChange(ap: T.APSelection | undefined) { + setEdited({ type: "AP", block: ap }); + } + function handleReset() { + setEdited(selectionToBlock(block)); + setEditing(false); + } + return ( +
+
setEditing(true)} + > + {!editing ? : } +
+
+ {editing && ( +
+ {edited.type === "NP" ? ( + + ) : ( + null} + negative={false} + /> + )} +
+ )} + {edited.block && ( + {edited.block} + )} +
+
+ ); } -export default EditableBlock; \ No newline at end of file +export default EditableBlock; diff --git a/src/content/verbs/GoingStems.tsx b/src/content/verbs/GoingStems.tsx index 2b0dbe4..d18109b 100644 --- a/src/content/verbs/GoingStems.tsx +++ b/src/content/verbs/GoingStems.tsx @@ -1,36 +1,123 @@ import Carousel from "../../components/Carousel"; import { - defaultTextOptions as opts, - InlinePs, - RootsAndStems, - getVerbInfo, - getAbilityRootsAndStems, - removeFVarients, - ensureNonComboVerbInfo, + defaultTextOptions as opts, + InlinePs, + RootsAndStems, + getVerbInfo, + getAbilityRootsAndStems, + removeFVarients, + ensureNonComboVerbInfo, } from "@lingdocs/ps-react"; export default function GoingStems() { - const items = [ - {"ts":1527815348,"i":3666,"p":"تلل","f":"tlul","g":"tlul","e":"to go","c":"v. intrans. irreg.","psp":"ځ","psf":"dz","ssp":"لاړ ش","ssf":"láaR sh","prp":"لاړ","prf":"láaR","ec":"go,goes,going,went,gone"}, - {"ts":1527815216,"i":6642,"p":"راتلل","f":"raatlúl","g":"raatlul","e":"to come","c":"v. intrans. irreg.","psp":"راځ","psf":"raadz","ssp":"راش","ssf":"ráash","prp":"راغلل","prf":"ráaghlul","pprtp":"راغلی","pprtf":"raaghúley","tppp":"راغی","tppf":"ráaghey","noOo":true,"separationAtP":2,"separationAtF":3,"ec":"come,comes,coming,came,come"}, - {"ts":1585228551150,"i":6062,"p":"درتلل","f":"dărtlul","g":"dartlul","e":"to come (to you / second person)","c":"v. intrans. irreg.","psp":"درځ","psf":"dărdz","ssp":"درش","ssf":"dársh","prp":"درغلل","prf":"dáraghlul","pprtp":"درغلی","pprtf":"dăraghúley","tppp":"درغی","tppf":"dáraghey","noOo":true,"separationAtP":2,"separationAtF":3,"ec":"come,comes,coming,came,come"}, - {"ts":1585228579997,"i":14282,"p":"ورتلل","f":"wărtlul","g":"wartlul","e":"to come / go over to (third person or place)","c":"v. intrans. irreg.","psp":"ورځ","psf":"wărdz","ssp":"ورش","ssf":"wársh","prp":"ورغلل","prf":"wáraghlul","pprtp":"ورغلی","pprtf":"wăraghúley","tppp":"ورغی","tppf":"wáraghey","noOo":true,"separationAtP":2,"separationAtF":3,"ec":"come,comes,coming,came,come"}, - ].map(entry => ({ entry })); - return { - const rs = getAbilityRootsAndStems( - ensureNonComboVerbInfo(getVerbInfo(item.entry)) - ); - return { - title: - {{ - ...removeFVarients(item.entry), - e: undefined, - }} - , - body: , - }; - }}/> -} \ No newline at end of file + const items = [ + { + ts: 1527815348, + i: 3666, + p: "تلل", + f: "tlul", + g: "tlul", + e: "to go", + c: "v. intrans. irreg.", + psp: "ځ", + psf: "dz", + ssp: "لاړ ش", + ssf: "láaR sh", + prp: "لاړ", + prf: "láaR", + ec: "go,goes,going,went,gone", + }, + { + ts: 1527815216, + i: 6642, + p: "راتلل", + f: "raatlúl", + g: "raatlul", + e: "to come", + c: "v. intrans. irreg.", + psp: "راځ", + psf: "raadz", + ssp: "راش", + ssf: "ráash", + prp: "راغلل", + prf: "ráaghlul", + pprtp: "راغلی", + pprtf: "raaghúley", + tppp: "راغی", + tppf: "ráaghey", + noOo: true, + separationAtP: 2, + separationAtF: 3, + ec: "come,comes,coming,came,come", + }, + { + ts: 1585228551150, + i: 6062, + p: "درتلل", + f: "dărtlul", + g: "dartlul", + e: "to come (to you / second person)", + c: "v. intrans. irreg.", + psp: "درځ", + psf: "dărdz", + ssp: "درش", + ssf: "dársh", + prp: "درغلل", + prf: "dáraghlul", + pprtp: "درغلی", + pprtf: "dăraghúley", + tppp: "درغی", + tppf: "dáraghey", + noOo: true, + separationAtP: 2, + separationAtF: 3, + ec: "come,comes,coming,came,come", + }, + { + ts: 1585228579997, + i: 14282, + p: "ورتلل", + f: "wărtlul", + g: "wartlul", + e: "to come / go over to (third person or place)", + c: "v. intrans. irreg.", + psp: "ورځ", + psf: "wărdz", + ssp: "ورش", + ssf: "wársh", + prp: "ورغلل", + prf: "wáraghlul", + pprtp: "ورغلی", + pprtf: "wăraghúley", + tppp: "ورغی", + tppf: "wáraghey", + noOo: true, + separationAtP: 2, + separationAtF: 3, + ec: "come,comes,coming,came,come", + }, + ].map((entry) => ({ entry })); + return ( + { + const rs = getAbilityRootsAndStems( + ensureNonComboVerbInfo(getVerbInfo(item.entry)) + ); + return { + title: ( + + ), + body: , + }; + }} + /> + ); +} diff --git a/src/games/sub-cores/EquativeGame.tsx b/src/games/sub-cores/EquativeGame.tsx index 6c73da8..283f2cc 100644 --- a/src/games/sub-cores/EquativeGame.tsx +++ b/src/games/sub-cores/EquativeGame.tsx @@ -1,17 +1,15 @@ import { useEffect, useState } from "react"; -import { - comparePs, -} from "../../lib/game-utils"; +import { comparePs } from "../../lib/game-utils"; import GameCore from "../GameCore"; import { - Types as T, - Examples, - defaultTextOptions as opts, - renderEP, - compileEP, - flattenLengths, - InlinePs, - grammarUnits, + Types as T, + Examples, + defaultTextOptions as opts, + renderEP, + compileEP, + flattenLengths, + InlinePs, + grammarUnits, } from "@lingdocs/ps-react"; import { randomEPSPool } from "./makeRandomEPS"; @@ -21,168 +19,215 @@ const amount = 12; const timeLimit = 100; type Question = { - EPS: T.EPSelectionComplete, - phrase: { ps: T.PsString[], e?: string[] }, - equative: T.EquativeRendered, + EPS: T.EPSelectionComplete; + phrase: { ps: T.PsString[]; e?: string[] }; + equative: T.EquativeRendered; }; -export default function EquativeGame({ inChapter, id, link, level }: { inChapter: boolean, id: string, link: string, level: T.EquativeTense | "allTenses" }) { - const epsPool = randomEPSPool(level); - function getQuestion(): Question { - const EPS = epsPool(); - const EP = renderEP(EPS); - const compiled = compileEP( - EP, - true, - { equative: true, kidsSection: true }, - ); - const phrase = { - ps: compiled.ps, - e: compiled.e, - }; - return { - EPS, - phrase, - equative: getEqFromRendered(EP), - }; +export default function EquativeGame({ + inChapter, + id, + link, + level, +}: { + inChapter: boolean; + id: string; + link: string; + level: T.EquativeTense | "allTenses"; +}) { + const epsPool = randomEPSPool(level); + function getQuestion(): Question { + const EPS = epsPool(); + const EP = renderEP(EPS); + const compiled = compileEP(EP, true, { equative: true, kidsSection: true }); + const phrase = { + ps: compiled.ps, + e: compiled.e, }; - - function Display({ question, callback }: QuestionDisplayProps) { - const [answer, setAnswer] = useState(""); - const [withBa, setWithBa] = useState(false); - const handleInput = ({ target: { value }}: React.ChangeEvent) => { - setAnswer(value); - } - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - const correct = comparePs(answer, question.equative.ps) - && (withBa === question.equative.hasBa); - if (correct) { - setAnswer(""); - } - callback(correct); - } - useEffect(() => { - if (level === "allTenses") setWithBa(false); - }, [question]); - - return
-
- - {/* @ts-ignore TODO: REMOVE AS P_INFLE */} - {modExs(question.phrase.ps, withBa)[0]} - - {question.phrase.e && question.phrase.e.map((e, i) => ( -
{e}
- ))} -
{humanReadableTense(question.EPS.equative.tense)} equative
-
-
-
- setWithBa(e.target.checked)} - /> - -
-
- -
-
- {/*
*/} - - {/*
*/} - {/*
+ return { + EPS, + phrase, + equative: getEqFromRendered(EP), + }; + } + + function Display({ question, callback }: QuestionDisplayProps) { + const [answer, setAnswer] = useState(""); + const [withBa, setWithBa] = useState(false); + const handleInput = ({ + target: { value }, + }: React.ChangeEvent) => { + setAnswer(value); + }; + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + const correct = + comparePs(answer, question.equative.ps) && + withBa === question.equative.hasBa; + if (correct) { + setAnswer(""); + } + callback(correct); + }; + useEffect(() => { + if (level === "allTenses") setWithBa(false); + }, [question]); + + return ( +
+
+ + {/* @ts-ignore TODO: REMOVE AS P_INFLE */} + {modExs(question.phrase.ps, withBa)[0]} + + {question.phrase.e && + question.phrase.e.map((e, i) => ( +
+ {e} +
+ ))} +
{humanReadableTense(question.EPS.equative.tense)} equative
+
+ +
+ setWithBa(e.target.checked)} + /> + +
+
+ +
+
+ {/*
*/} + + {/*
*/} + {/*
Type Enter to check
*/} -
- -
- } - - function Instructions() { - return
-

- Fill in the blank with the correct {level === "allTenses" ? "" : humanReadableTense(level)} equative -

- {level === "allTenses" &&
⚠ All tenses included...
} -
; - } +
+ +
+ ); + } - return +

+ Fill in the blank with the correct{" "} + {level === "allTenses" ? "" : humanReadableTense(level)} equative +

+ {level === "allTenses" &&
⚠ All tenses included...
} +
+ ); + } + + return ( + -}; - -function DisplayCorrectAnswer({ question }: { question: Question }): JSX.Element { - return
-
- {flattenLengths(question.equative.ps).reduce(((accum, curr, i): JSX.Element[] => ( - [ - ...accum, - ...i > 0 ? [ or ] : [], - {curr.p}, - ] - )), [] as JSX.Element[])} -
-
{question.equative.hasBa ? "with" : "without"} a {grammarUnits.baParticle} in the kids' section.
-
; + ); } -function modExs(exs: T.PsString[], withBa: boolean): { p: JSX.Element, f: JSX.Element }[] { - return exs.map(ps => { - if (!ps.p.includes(" ___ ")) { - return { - p: <>{ps.p}, - f: <>{ps.f}, - }; - } - const splitP = ps.p.split(" ___ "); - const splitF = ps.f.split(" ___ "); - return { - p: <>{splitP[0]} {withBa ? "به" : "__"} {splitP[1]}, - f: <>{splitF[0]} {withBa ? "ba" : "__"} {splitF[1]}, - }; - }); + +function DisplayCorrectAnswer({ + question, +}: { + question: Question; +}): JSX.Element { + return ( +
+
+ {flattenLengths(question.equative.ps).reduce( + (accum, curr, i): JSX.Element[] => [ + ...accum, + ...(i > 0 ? [ or ] : []), + {curr.p}, + ], + [] as JSX.Element[] + )} +
+
+ {question.equative.hasBa ? "with" : "without"} a{" "} + in the kids' + section. +
+
+ ); +} +function modExs( + exs: T.PsString[], + withBa: boolean +): { p: JSX.Element; f: JSX.Element }[] { + return exs.map((ps) => { + if (!ps.p.includes(" ___ ")) { + return { + p: <>{ps.p}, + f: <>{ps.f}, + }; + } + const splitP = ps.p.split(" ___ "); + const splitF = ps.f.split(" ___ "); + return { + p: ( + <> + {splitP[0]}{" "} + {withBa ? "به" : "__"}{" "} + {splitP[1]} + + ), + f: ( + <> + {splitF[0]}{" "} + {withBa ? "ba" : "__"}{" "} + {splitF[1]} + + ), + }; + }); } function humanReadableTense(tense: T.EquativeTense | "allProduce"): string { - return tense === "allProduce" - ? "" - : tense === "pastSubjunctive" - ? "past subjunctive" - : tense === "wouldBe" - ? `"would be"` - : tense === "wouldHaveBeen" - ? `"would have been"` - : tense; + return tense === "allProduce" + ? "" + : tense === "pastSubjunctive" + ? "past subjunctive" + : tense === "wouldBe" + ? `"would be"` + : tense === "wouldHaveBeen" + ? `"would have been"` + : tense; } - - function getEqFromRendered(e: T.EPRendered): T.EquativeRendered { - const eblock = e.blocks[0].find(x => x.block.type === "equative"); - if (!eblock || eblock.block.type !== "equative") throw new Error("Error getting equative block"); - return eblock.block.equative; -} \ No newline at end of file + const eblock = e.blocks[0].find((x) => x.block.type === "equative"); + if (!eblock || eblock.block.type !== "equative") + throw new Error("Error getting equative block"); + return eblock.block.equative; +} diff --git a/src/games/sub-cores/NPAdjGame.tsx b/src/games/sub-cores/NPAdjGame.tsx index 5bf5fa0..c6bae7f 100644 --- a/src/games/sub-cores/NPAdjGame.tsx +++ b/src/games/sub-cores/NPAdjGame.tsx @@ -1,13 +1,13 @@ import GameCore from "../GameCore"; import { - Types as T, - renderNPSelection, - getEnglishFromRendered, - getPashtoFromRendered, - renderAPSelection, - InlinePs, - defaultTextOptions as opts, - concatPsString, + Types as T, + renderNPSelection, + getEnglishFromRendered, + getPashtoFromRendered, + renderAPSelection, + InlinePs, + defaultTextOptions as opts, + concatPsString, } from "@lingdocs/ps-react"; import { makeNPAdjGenerator } from "../../lib/block-generators/np-adj-generator"; import { useState } from "react"; @@ -19,141 +19,183 @@ const amount = 16; const timeLimit = 270; type Question = { - selection: T.NPSelection | T.APSelection, - answer: T.PsString[], - english: string, + selection: T.NPSelection | T.APSelection; + answer: T.PsString[]; + english: string; }; type Level = "hints" | "no-hints" | "sandwiches"; -const NPAdjWriting: GameSubCore = ({ inChapter, id, link, level }: { - inChapter: boolean, - id: string, - link: string, - level: Level, +const NPAdjWriting: GameSubCore = ({ + inChapter, + id, + link, + level, +}: { + inChapter: boolean; + id: string; + link: string; + level: Level; }) => { - const npPool = makeNPAdjGenerator(level === "sandwiches" ? "low" : "high"); + const npPool = makeNPAdjGenerator(level === "sandwiches" ? "low" : "high"); - function getQuestion(): Question { - const np = npPool(); - const selection: T.NPSelection | T.APSelection = level === "sandwiches" - ? makeSandwich(np) : np; - const rendered: T.Rendered | T.Rendered = selection.type === "AP" - ? renderAPSelection(selection, 0) // WOULD BE CLEANER IF THIS WAS JUST A PURE SANDWICH, NOT AT AP - : renderNPSelection(np, false, false, "subject", "none", false); - const answer = getPashtoFromRendered(rendered, false); - return { - selection, - answer, - english: getEnglishFromRendered(rendered) || "ERROR", - }; + function getQuestion(): Question { + const np = npPool(); + const selection: T.NPSelection | T.APSelection = + level === "sandwiches" ? makeSandwich(np) : np; + const rendered: T.Rendered | T.Rendered = + selection.type === "AP" + ? renderAPSelection(selection, 0) // WOULD BE CLEANER IF THIS WAS JUST A PURE SANDWICH, NOT AT AP + : renderNPSelection(np, false, false, "subject", "none", false); + const answer = getPashtoFromRendered(rendered, false); + return { + selection, + answer, + english: getEnglishFromRendered(rendered) || "ERROR", }; - - function Display({ question, callback }: QuestionDisplayProps) { - const [answer, setAnswer] = useState(""); - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - const correct = comparePs(answer, question.answer); - if (correct) { - setAnswer(""); - } - callback(correct); - } - if (!( - (question.selection.type === "AP" && question.selection.selection.type === "sandwich" && question.selection.selection.inside.selection.type === "noun") - || - (question.selection.type === "NP" && question.selection.selection.type === "noun") - )) { - throw new Error("QUESTION ERROR - BAD SELECTION") - } - const nounSelection: T.NounSelection = question.selection.type === "AP" - ? question.selection.selection.inside.selection as T.NounSelection // ts being dumb - : question.selection.selection; - const adjEntry: T.AdjectiveEntry | undefined = nounSelection.adjectives[0]?.entry; - if (!adjEntry) { - throw new Error("QUESTION ERROR - MISSING ADJECTIVE"); - } - const handleInput = ({ target: { value }}: React.ChangeEvent) => { - setAnswer(value); - } - const sandwich = question.selection.type === "AP" - ? question.selection.selection - : undefined; - return
-
-
- - -
- {sandwich &&
- - {concatPsString(sandwich.before, " ... ", sandwich.after)} - -
} -
- {question.english} -
-
-
- -
-
- -
-
-
-
- } - - function Instructions() { - return
-

Write the {level === "sandwiches" ? "sandwich including the" : ""} adjective and noun together with the proper inflections.

-
- } + } - return ) { + const [answer, setAnswer] = useState(""); + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + const correct = comparePs(answer, question.answer); + if (correct) { + setAnswer(""); + } + callback(correct); + }; + if ( + !( + (question.selection.type === "AP" && + question.selection.selection.type === "sandwich" && + question.selection.selection.inside.selection.type === "noun") || + (question.selection.type === "NP" && + question.selection.selection.type === "noun") + ) + ) { + throw new Error("QUESTION ERROR - BAD SELECTION"); + } + const nounSelection: T.NounSelection = + question.selection.type === "AP" + ? (question.selection.selection.inside.selection as T.NounSelection) // ts being dumb + : question.selection.selection; + const adjEntry: T.AdjectiveEntry | undefined = + nounSelection.adjectives[0]?.entry; + if (!adjEntry) { + throw new Error("QUESTION ERROR - MISSING ADJECTIVE"); + } + const handleInput = ({ + target: { value }, + }: React.ChangeEvent) => { + setAnswer(value); + }; + const sandwich = + question.selection.type === "AP" + ? question.selection.selection + : undefined; + return ( +
+
+
+ + +
+ {sandwich && ( +
+ +
+ )} +
{question.english}
+
+
+ +
+
+ +
+
+
+
+ ); + } + + function Instructions() { + return ( +
+

+ Write the {level === "sandwiches" ? "sandwich including the" : ""}{" "} + adjective and noun together with the proper inflections. +

+
+ ); + } + + return ( + + ); }; -function DisplayCorrectAnswer({ question }: { question: Question }): JSX.Element { - // TODO: extract this reduces for the or, or different variations, used in VerbGame (etc.?) - return
-
- {question.answer.reduce(((accum, curr, i): JSX.Element[] => ( - [ - ...accum, - ...i > 0 ? [ or ] : [], - {curr.p} - {curr.f}, - ] - )), [] as JSX.Element[])} -
-
; +function DisplayCorrectAnswer({ + question, +}: { + question: Question; +}): JSX.Element { + // TODO: extract this reduces for the or, or different variations, used in VerbGame (etc.?) + return ( +
+
+ {question.answer.reduce( + (accum, curr, i): JSX.Element[] => [ + ...accum, + ...(i > 0 ? [ or ] : []), + + {curr.p} - {curr.f} + , + ], + [] as JSX.Element[] + )} +
+
+ ); } export default NPAdjWriting; diff --git a/src/games/sub-cores/PerfectGame.tsx b/src/games/sub-cores/PerfectGame.tsx index 4df667b..3bbf811 100644 --- a/src/games/sub-cores/PerfectGame.tsx +++ b/src/games/sub-cores/PerfectGame.tsx @@ -270,8 +270,8 @@ const VerbGame: GameSubCore = ({ className="form-check-label text-muted" htmlFor="baCheckbox" > - with {grammarUnits.baParticle}{" "} - in the kids' section + with in + the kids' section
)} @@ -352,7 +352,7 @@ function DisplayCorrectAnswer({
{verbHasBa(question.rendered) ? "with" : "without"} a{" "} - {grammarUnits.baParticle} in the kids' + in the kids' section.
diff --git a/src/games/sub-cores/VerbFormulas.tsx b/src/games/sub-cores/VerbFormulas.tsx index 092be0e..abed9d3 100644 --- a/src/games/sub-cores/VerbFormulas.tsx +++ b/src/games/sub-cores/VerbFormulas.tsx @@ -1,10 +1,10 @@ import GameCore from "../GameCore"; import { - humanReadableVerbForm, - Types as T, - InlinePs, - grammarUnits, - defaultTextOptions as opts, + humanReadableVerbForm, + Types as T, + InlinePs, + grammarUnits, + defaultTextOptions as opts, } from "@lingdocs/ps-react"; import { makePool } from "../../lib/pool"; import { CSSProperties, useEffect, useState } from "react"; @@ -14,347 +14,439 @@ import { isImperativeTense } from "@lingdocs/ps-react/dist/lib/src/type-predicat const amount = 12; const timeLimit = 125; -type StemRoot = "imperfective stem" | "perfective stem" | "imperfective root" | "perfective root"; -type Ending = "present" | "past" | "imperative"; +type StemRoot = + | "imperfective stem" + | "perfective stem" + | "imperfective root" + | "perfective root"; +type Ending = "present" | "past" | "imperative"; type Formula = { - ba: boolean, - mu: boolean, - stemRoot: StemRoot, - ending: Ending, + ba: boolean; + mu: boolean; + stemRoot: StemRoot; + ending: Ending; }; type Question = { - tense: T.VerbTense | T.ImperativeTense | "negative imperative", - formula: Formula, -} - -const questions: Question[] = [ - { - tense: "presentVerb", - formula: { - ba: false, - mu: false, - stemRoot: "imperfective stem", - ending: "present", - }, - }, - { - tense: "subjunctiveVerb", - formula: { - ba: false, - mu: false, - stemRoot: "perfective stem", - ending: "present", - }, - }, - { - tense: "imperfectiveFuture", - formula: { - ba: true, - mu: false, - stemRoot: "imperfective stem", - ending: "present", - }, - }, - { - tense: "perfectiveFuture", - formula: { - ba: true, - mu: false, - stemRoot: "perfective stem", - ending: "present", - }, - }, - { - tense: "imperfectivePast", - formula: { - ba: false, - mu: false, - stemRoot: "imperfective root", - ending: "past", - }, - }, - { - tense: "perfectivePast", - formula: { - ba: false, - mu: false, - stemRoot: "perfective root", - ending: "past", - }, - }, - { - tense: "habitualImperfectivePast", - formula: { - ba: true, - mu: false, - stemRoot: "imperfective root", - ending: "past", - }, - }, - { - tense: "habitualPerfectivePast", - formula: { - ba: true, - mu: false, - stemRoot: "perfective root", - ending: "past", - }, - }, - { - tense: "perfectiveImperative", - formula: { - ba: false, - mu: false, - stemRoot: "perfective stem", - ending: "imperative", - }, - }, - { - tense: "imperfectiveImperative", - formula: { - ba: false, - mu: false, - stemRoot: "imperfective stem", - ending: "imperative", - }, - }, - { - tense: "negative imperative", - formula: { - ba: false, - mu: true, - stemRoot: "imperfective stem", - ending: "imperative", - }, - } -]; - -export default function VerbFormulas({ inChapter, id, link, level }: { inChapter: boolean, id: string, link: string, level: "all" }) { - const questionsPool = makePool(questions); - function getQuestion() { - return questionsPool(); - } - function Instructions() { - return

Pick the formula for each verb tense

; - } - return + tense: T.VerbTense | T.ImperativeTense | "negative imperative"; + formula: Formula; }; +const questions: Question[] = [ + { + tense: "presentVerb", + formula: { + ba: false, + mu: false, + stemRoot: "imperfective stem", + ending: "present", + }, + }, + { + tense: "subjunctiveVerb", + formula: { + ba: false, + mu: false, + stemRoot: "perfective stem", + ending: "present", + }, + }, + { + tense: "imperfectiveFuture", + formula: { + ba: true, + mu: false, + stemRoot: "imperfective stem", + ending: "present", + }, + }, + { + tense: "perfectiveFuture", + formula: { + ba: true, + mu: false, + stemRoot: "perfective stem", + ending: "present", + }, + }, + { + tense: "imperfectivePast", + formula: { + ba: false, + mu: false, + stemRoot: "imperfective root", + ending: "past", + }, + }, + { + tense: "perfectivePast", + formula: { + ba: false, + mu: false, + stemRoot: "perfective root", + ending: "past", + }, + }, + { + tense: "habitualImperfectivePast", + formula: { + ba: true, + mu: false, + stemRoot: "imperfective root", + ending: "past", + }, + }, + { + tense: "habitualPerfectivePast", + formula: { + ba: true, + mu: false, + stemRoot: "perfective root", + ending: "past", + }, + }, + { + tense: "perfectiveImperative", + formula: { + ba: false, + mu: false, + stemRoot: "perfective stem", + ending: "imperative", + }, + }, + { + tense: "imperfectiveImperative", + formula: { + ba: false, + mu: false, + stemRoot: "imperfective stem", + ending: "imperative", + }, + }, + { + tense: "negative imperative", + formula: { + ba: false, + mu: true, + stemRoot: "imperfective stem", + ending: "imperative", + }, + }, +]; + +export default function VerbFormulas({ + inChapter, + id, + link, + level, +}: { + inChapter: boolean; + id: string; + link: string; + level: "all"; +}) { + const questionsPool = makePool(questions); + function getQuestion() { + return questionsPool(); + } + function Instructions() { + return

Pick the formula for each verb tense

; + } + return ( + + ); +} + function Display({ question, callback }: QuestionDisplayProps) { - const [ba, setBa] = useState(false); - const [mu, setMu] = useState(false); - const [stemRoot, setStemRoot] = useState(""); - const [ending, setEnding] = useState(""); - useEffect(() => { - setBa(false); - setStemRoot(""); - setEnding(""); - setMu(false); - }, [question]); - const canSubmit = !!(stemRoot && ending); - const showMu = question.tense === "negative imperative" || isImperativeTense(question.tense); - function handleSubmit() { - const { formula } = question; - callback( - (ba === formula.ba) - && - (mu === formula.mu) - && - (stemRoot === formula.stemRoot) - && - (ending === formula.ending) - ); - } - return
-
-

- {humanReadableT(question.tense)} -

-
-
- - {showMu && } - - - -
- {printFormula({ ba, stemRoot, ending, mu })} + const [ba, setBa] = useState(false); + const [mu, setMu] = useState(false); + const [stemRoot, setStemRoot] = useState(""); + const [ending, setEnding] = useState(""); + useEffect(() => { + setBa(false); + setStemRoot(""); + setEnding(""); + setMu(false); + }, [question]); + const canSubmit = !!(stemRoot && ending); + const showMu = + question.tense === "negative imperative" || + isImperativeTense(question.tense); + function handleSubmit() { + const { formula } = question; + callback( + ba === formula.ba && + mu === formula.mu && + stemRoot === formula.stemRoot && + ending === formula.ending + ); + } + return ( +
+
+

{humanReadableT(question.tense)}

+
+
+ + {showMu && } + + + +
+ {printFormula({ ba, stemRoot, ending, mu })}
+ ); } -function humanReadableT(tense: T.VerbTense | T.ImperativeTense | "negative imperative"): string { - if (tense === "negative imperative") { - return tense; - } - return humanReadableVerbForm(tense); +function humanReadableT( + tense: T.VerbTense | T.ImperativeTense | "negative imperative" +): string { + if (tense === "negative imperative") { + return tense; + } + return humanReadableVerbForm(tense); } -function printFormula({ mu, ba, stemRoot, ending }: { - mu: boolean, - ba: boolean, - stemRoot: StemRoot | "", - ending: Ending | "", +function printFormula({ + mu, + ba, + stemRoot, + ending, +}: { + mu: boolean; + ba: boolean; + stemRoot: StemRoot | ""; + ending: Ending | ""; }): string { - const elements = [ - mu ? "mu" : undefined, - ba ? "ba" : undefined, - stemRoot, - ending ? `${ending} ending` : undefined, - ].filter(x => x) as string[]; - return elements.join(" + "); + const elements = [ + mu ? "mu" : undefined, + ba ? "ba" : undefined, + stemRoot, + ending ? `${ending} ending` : undefined, + ].filter((x) => x) as string[]; + return elements.join(" + "); } -function DisplayCorrectAnswer({ question }: { question: Question }): JSX.Element { - return
- {printFormula(question.formula)} -
; -} - -function EndingPicker({ onChange, value }: { value: Ending | "", onChange: (e: Ending | "") => void }) { - const options: { label: string, value: Ending }[] = [ - { label: "Present", value: "present" }, - { label: "Past", value: "past" }, - { label: "Imperative", value: "imperative" }, - ]; - function handleClick(e: Ending) { - // onChange(ending === e ? "" : e); - onChange(e); - } - return
- Ending: -
- {options.map((option) => ( - - ))} -
-
; -} - -function BaPicker({ onChange, value }: { value: boolean, onChange: (b: boolean) => void }) { - return
- onChange(e.target.checked)} - /> - +function DisplayCorrectAnswer({ + question, +}: { + question: Question; +}): JSX.Element { + return ( +
+ {printFormula(question.formula)}
+ ); } -function MuPicker({ onChange, value }: { value: boolean, onChange: (b: boolean) => void }) { - return
- onChange(e.target.checked)} - /> - +function EndingPicker({ + onChange, + value, +}: { + value: Ending | ""; + onChange: (e: Ending | "") => void; +}) { + const options: { label: string; value: Ending }[] = [ + { label: "Present", value: "present" }, + { label: "Past", value: "past" }, + { label: "Imperative", value: "imperative" }, + ]; + function handleClick(e: Ending) { + // onChange(ending === e ? "" : e); + onChange(e); + } + return ( +
+ Ending: +
+ {options.map((option) => ( + + ))} +
+ ); } -function RootsAndStemsPicker({ onChange, value }: { value: StemRoot | "", onChange: (s: StemRoot | "" ) => void }) { - const colClass = "col col-md-5 px-0 mb-1"; - const rowClass = "row justify-content-between"; - const title: CSSProperties = { - fontWeight: "bolder", - paddingBottom: "1.75rem", - paddingTop: "1.75rem", - }; - const highlight = { - background: "rgba(255, 227, 10, 0.6)", - }; - function handleStemRootClick(s: StemRoot) { - onChange(value === s ? "" : s); - } - return
void; +}) { + return ( +
+ onChange(e.target.checked)} + /> + +
+ ); +} + +function MuPicker({ + onChange, + value, +}: { + value: boolean; + onChange: (b: boolean) => void; +}) { + return ( +
+ onChange(e.target.checked)} + /> + +
+ ); +} + +function RootsAndStemsPicker({ + onChange, + value, +}: { + value: StemRoot | ""; + onChange: (s: StemRoot | "") => void; +}) { + const colClass = "col col-md-5 px-0 mb-1"; + const rowClass = "row justify-content-between"; + const title: CSSProperties = { + fontWeight: "bolder", + paddingBottom: "1.75rem", + paddingTop: "1.75rem", + }; + const highlight = { + background: "rgba(255, 227, 10, 0.6)", + }; + function handleStemRootClick(s: StemRoot) { + onChange(value === s ? "" : s); + } + return ( +
-
-
-
- -
-
-
-
- -
-
-
-
-
-
-
handleStemRootClick("imperfective stem")}> -
Imperfective Stem
-
-
-
-
handleStemRootClick("perfective stem")}> -
Perfective Stem
-
-
-
-
-
-
handleStemRootClick("imperfective root")}> -
Imperfective Root
-
-
-
-
-
handleStemRootClick("perfective root")}> -
Perfective Root
-
-
-
+ backgroundSize: "50%", + }} + > +
+
+
+ +
+
+
+
+ +
+
-
; +
+
+
handleStemRootClick("imperfective stem")} + > +
Imperfective Stem
+
+
+
+
handleStemRootClick("perfective stem")} + > +
Perfective Stem
+
+
+
+
+
+
handleStemRootClick("imperfective root")} + > +
Imperfective Root
+
+
+
+
+
handleStemRootClick("perfective root")} + > +
Perfective Root
+
+
+
+
+
+
+ ); } - diff --git a/src/games/sub-cores/VerbGame.tsx b/src/games/sub-cores/VerbGame.tsx index 91e63ae..9fa48e4 100644 --- a/src/games/sub-cores/VerbGame.tsx +++ b/src/games/sub-cores/VerbGame.tsx @@ -276,8 +276,8 @@ const VerbGame: GameSubCore = ({ onChange={(e) => setWithBa(e.target.checked)} />
@@ -400,7 +400,7 @@ function DisplayCorrectAnswer({
{verbHasBa(question.rendered) ? "with" : "without"} a{" "} - {grammarUnits.baParticle} in the kids' + in the kids' section.
diff --git a/yarn.lock b/yarn.lock index 806183a..5e63279 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1597,10 +1597,10 @@ rambda "^6.7.0" react-select "^5.2.2" -"@lingdocs/ps-react@^7.7.3": - version "7.7.3" - resolved "https://npm.lingdocs.com/@lingdocs/ps-react/-/ps-react-7.7.3.tgz#353b6ddabdfabb4eae45a1d8554adb360f7238fc" - integrity sha512-TSK5kgyCEHTmJRH+9XfchVPUVvsjOfsLlrZlW4PL95LhvBD1dh5CazZDQlPV99CLZGz3jVf9VKpiQP7RdGYTrg== +"@lingdocs/ps-react@^7.7.4": + version "7.7.4" + resolved "https://npm.lingdocs.com/@lingdocs/ps-react/-/ps-react-7.7.4.tgz#6529c1728828cce6d9e550a0323463bd2ae55ffc" + integrity sha512-K7SnvOXITl3DCY9l4ifKKnjC6Uw3AwvjWlV87l+YtboCG7B277iYhdVrb8/6bxzUhGuSAtSGx982bN7gSuKIxA== dependencies: "@formkit/auto-animate" "^1.0.0-beta.3" classnames "^2.5.1"