starting work on phrase builder
This commit is contained in:
parent
0553076bab
commit
30e5697452
|
@ -0,0 +1,91 @@
|
|||
import Select from "react-select";
|
||||
import {
|
||||
makeVerbSelectOption,
|
||||
zIndexProps,
|
||||
} from "./np-picker/picker-tools";
|
||||
import {
|
||||
Types as T,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
|
||||
const tenseOptions = [{
|
||||
label: "present",
|
||||
value: "present",
|
||||
}, {
|
||||
label: "subjunctive",
|
||||
value: "subjunctive",
|
||||
}];
|
||||
|
||||
function makeVerbSelection(verb: VerbEntry, oldVerbSelection?: VerbSelection): VerbSelection {
|
||||
function getTransObjFromOldVerbSelection() {
|
||||
if (!oldVerbSelection || oldVerbSelection.object === "none" || typeof oldVerbSelection.object === "number") return undefined;
|
||||
return oldVerbSelection.object;
|
||||
}
|
||||
// TODO: more complex types and unchangeable dynamic compound objects
|
||||
const verbType: "intrans" | "trans" | "gramm trans" = verb.entry.c?.includes("v. intrans.")
|
||||
? "intrans"
|
||||
: verb.entry.c?.includes("v. gramm. trans.")
|
||||
? "gramm trans"
|
||||
: "trans";
|
||||
const object = verbType === "gramm trans"
|
||||
? T.Person.ThirdPlurMale
|
||||
: verbType === "trans"
|
||||
? getTransObjFromOldVerbSelection()
|
||||
: "none";
|
||||
console.log({ verbType, object });
|
||||
return {
|
||||
type: "verb",
|
||||
verb,
|
||||
tense: oldVerbSelection ? oldVerbSelection.tense : "present",
|
||||
object,
|
||||
};
|
||||
}
|
||||
|
||||
function VerbPicker({ onChange, verb, verbs }: { verbs: VerbEntry[], verb: VerbSelection | undefined, onChange: (p: VerbSelection) => void }) {
|
||||
const options = verbs.map(makeVerbSelectOption)
|
||||
function onEntrySelect({ value }: { label: string, value: string }) {
|
||||
const v = verbs.find(v => v.entry.ts.toString() === value);
|
||||
if (!v) {
|
||||
console.error("entry not found");
|
||||
return;
|
||||
}
|
||||
onChange(makeVerbSelection(v, verb));
|
||||
}
|
||||
function onTenseSelect({ value }: { label: string, value: "present" | "subjunctive" }) {
|
||||
if (verb) {
|
||||
console.log("changing to", value)
|
||||
onChange({
|
||||
...verb,
|
||||
tense: value,
|
||||
});
|
||||
}
|
||||
}
|
||||
return <div style={{ maxWidth: "225px" }}>
|
||||
<div>Verb:</div>
|
||||
<Select
|
||||
value={verb && verb.verb.entry.ts.toString()}
|
||||
// @ts-ignore
|
||||
onChange={onEntrySelect}
|
||||
className="mb-2"
|
||||
// @ts-ignore
|
||||
options={options}
|
||||
isSearchable
|
||||
// // @ts-ignore
|
||||
placeholder={verb ? options.find(o => o.value === (verb.verb.entry).ts.toString())?.label : "Select Verb..."}
|
||||
{...zIndexProps}
|
||||
/>
|
||||
<div>Tense:</div>
|
||||
<Select
|
||||
value={verb && verb.tense}
|
||||
// @ts-ignore
|
||||
onChange={onTenseSelect}
|
||||
className="mb-2"
|
||||
// @ts-ignore
|
||||
options={tenseOptions}
|
||||
isSearchable
|
||||
placeholder={verb ? tenseOptions.find(o => o.value === verb.tense)?.value : "Select Tense..."}
|
||||
{...zIndexProps}
|
||||
/>
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default VerbPicker;
|
|
@ -0,0 +1,69 @@
|
|||
import Select from "react-select";
|
||||
import {
|
||||
makeSelectOption,
|
||||
zIndexProps,
|
||||
makeNounSelection,
|
||||
} from "./picker-tools";
|
||||
import {
|
||||
ButtonSelect,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
|
||||
|
||||
function NPNounPicker({ onChange, noun, nouns }: { nouns: NounEntry[], noun: NounSelection | undefined, onChange: (p: NounSelection) => void }) {
|
||||
const options = nouns.map(makeSelectOption)
|
||||
function onEntrySelect({ value }: { label: string, value: string }) {
|
||||
const entry = nouns.find(n => n.ts.toString() === value);
|
||||
if (!entry) {
|
||||
console.error("entry not found");
|
||||
return;
|
||||
}
|
||||
onChange(makeNounSelection(entry));
|
||||
}
|
||||
return <div style={{ maxWidth: "225px" }}>
|
||||
<Select
|
||||
value={noun && noun.entry.ts.toString()}
|
||||
// @ts-ignore
|
||||
onChange={onEntrySelect}
|
||||
className="mb-2"
|
||||
// @ts-ignore
|
||||
options={options}
|
||||
isSearchable
|
||||
// // @ts-ignore
|
||||
|
||||
placeholder={noun ? options.find(o => o.value === (noun.entry).ts.toString())?.label : "Select Noun..."}
|
||||
{...zIndexProps}
|
||||
/>
|
||||
{noun && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
||||
<div>
|
||||
{noun.changeGender ? <ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: "Masc", value: "masc" },
|
||||
{ label: "Fem", value: "fem" },
|
||||
]}
|
||||
value={noun.gender}
|
||||
handleChange={(g) => {
|
||||
if (!noun.changeGender) return;
|
||||
onChange(noun.changeGender(g));
|
||||
}}
|
||||
/> : noun.gender === "masc" ? "Masc." : "Fem."}
|
||||
</div>
|
||||
<div>
|
||||
{noun.changeNumber ? <ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: "Sing.", value: "sing" },
|
||||
{ label: "Plur.", value: "plur" },
|
||||
]}
|
||||
value={noun.number}
|
||||
handleChange={(n) => {
|
||||
if (!noun.changeNumber) return;
|
||||
onChange(noun.changeNumber(n));
|
||||
}}
|
||||
/> : noun.number === "sing" ? "Sing." : "Plur."}
|
||||
</div>
|
||||
</div>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default NPNounPicker;
|
|
@ -0,0 +1,44 @@
|
|||
import Select from "react-select";
|
||||
import {
|
||||
makeSelectOption,
|
||||
zIndexProps,
|
||||
} from "./picker-tools";
|
||||
|
||||
function makeParticipleSelection(verb: VerbEntry): ParticipleSelection {
|
||||
return {
|
||||
type: "participle",
|
||||
verb,
|
||||
};
|
||||
}
|
||||
|
||||
function NPParticiplePicker({ onChange, participle, verbs }: { verbs: VerbEntry[], participle: ParticipleSelection | undefined, onChange: (p: ParticipleSelection) => void }) {
|
||||
const options = verbs.map(makeSelectOption)
|
||||
function onEntrySelect({ value }: { label: string, value: string }) {
|
||||
const verb = verbs.find(v => v.entry.ts.toString() === value);
|
||||
if (!verb) {
|
||||
console.error("entry not found");
|
||||
return;
|
||||
}
|
||||
onChange(makeParticipleSelection(verb));
|
||||
}
|
||||
return <div style={{ maxWidth: "225px" }}>
|
||||
<Select
|
||||
value={participle && participle.verb.entry.ts.toString()}
|
||||
// @ts-ignore
|
||||
onChange={onEntrySelect}
|
||||
className="mb-2"
|
||||
// @ts-ignore
|
||||
options={options}
|
||||
isSearchable
|
||||
// // @ts-ignore
|
||||
placeholder={participle ? options.find(o => o.value === (participle.verb.entry).ts.toString())?.label : "Select Participle..."}
|
||||
{...zIndexProps}
|
||||
/>
|
||||
{participle && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
||||
<div>Masc.</div>
|
||||
<div>Plur.</div>
|
||||
</div>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default NPParticiplePicker;
|
|
@ -1,9 +1,12 @@
|
|||
import PronounPicker from "./NPPronounPicker";
|
||||
import { getEnglishPronoun } from "../../lib/english-pronoun-tools";
|
||||
import NounPicker from "./NPNounPicker";
|
||||
import ParticiplePicker from "./NPParticiplePicker";
|
||||
// import { getEnglishPronoun } from "../../lib/english-pronoun-tools";
|
||||
// import { ButtonSelect } from "@lingdocs/pashto-inflector";
|
||||
import { randomPerson } from "../../lib/np-tools";
|
||||
import { useState } from "react";
|
||||
import { capitalizeFirstLetter } from "../../lib/text-tools";
|
||||
import { nouns, verbs } from "../../words/words";
|
||||
// import { capitalizeFirstLetter } from "../../lib/text-tools";
|
||||
|
||||
const npTypes: NPType[] = ["noun", "pronoun", "participle"];
|
||||
|
||||
|
@ -19,17 +22,18 @@ function NPPicker({ np, onChange }: { onChange: (nps: NPSelection | undefined) =
|
|||
const person = randomPerson();
|
||||
const pronoun: PronounSelection = {
|
||||
type: "pronoun",
|
||||
e: capitalizeFirstLetter(getEnglishPronoun(person, "subject")),
|
||||
person,
|
||||
distance: "far",
|
||||
};
|
||||
setNpType(ntp);
|
||||
onChange(pronoun);
|
||||
} else {
|
||||
onChange(undefined);
|
||||
setNpType(ntp);
|
||||
}
|
||||
}
|
||||
return <div>
|
||||
{!np ?
|
||||
return <div style={{ maxWidth: "300px"}}>
|
||||
{!npType ?
|
||||
<div>
|
||||
{npTypes.map((npt) => (
|
||||
<button
|
||||
|
@ -42,12 +46,18 @@ function NPPicker({ np, onChange }: { onChange: (nps: NPSelection | undefined) =
|
|||
</button>
|
||||
))}
|
||||
</div>
|
||||
: <div onClick={handleClear}>X</div>}
|
||||
{np &&
|
||||
(np.type === "pronoun"
|
||||
: <button className="btn btn-sm btn-light mb-2" onClick={handleClear}>X</button>}
|
||||
{np ?
|
||||
((np.type === "pronoun"
|
||||
? <PronounPicker pronoun={np} onChange={onChange} />
|
||||
: <div>Not Implemented</div>)
|
||||
}
|
||||
: np.type === "noun"
|
||||
? <NounPicker nouns={nouns} noun={np} onChange={onChange} />
|
||||
: <ParticiplePicker verbs={verbs} participle={np} onChange={onChange} />))
|
||||
: (npType === "noun")
|
||||
? <NounPicker nouns={nouns} noun={np} onChange={onChange} />
|
||||
: (npType === "participle")
|
||||
? <ParticiplePicker verbs={verbs} participle={np} onChange={onChange} />
|
||||
: null}
|
||||
</div>;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@ import {
|
|||
Types as T,
|
||||
ButtonSelect,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
import { getEnglishPronoun } from "../../lib/english-pronoun-tools";
|
||||
import { capitalizeFirstLetter } from "../../lib/text-tools";
|
||||
import useStickyState from "../../useStickyState";
|
||||
|
||||
const gColors = {
|
||||
|
@ -60,7 +58,6 @@ function NPPronounPicker({ onChange, pronoun }: { pronoun: PronounSelection, onC
|
|||
const person = pickerStateToPerson({ ...p, row, col });
|
||||
onChange({
|
||||
...pronoun,
|
||||
e: capitalizeFirstLetter(getEnglishPronoun(person, "subject")),
|
||||
person,
|
||||
});
|
||||
}
|
||||
|
@ -68,7 +65,6 @@ function NPPronounPicker({ onChange, pronoun }: { pronoun: PronounSelection, onC
|
|||
const person = pickerStateToPerson({ ...p, gender });
|
||||
onChange({
|
||||
...pronoun,
|
||||
e: capitalizeFirstLetter(getEnglishPronoun(person, "subject")),
|
||||
person,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
import {
|
||||
isNounEntry,
|
||||
isAdjectiveEntry,
|
||||
isAdverbEntry,
|
||||
isPluralNounEntry,
|
||||
isMascNounEntry,
|
||||
isUnisexNounEntry,
|
||||
isVerbEntry,
|
||||
} from "../../lib/type-predicates";
|
||||
import {
|
||||
getEnglishParticiple,
|
||||
getEnglishVerb,
|
||||
} from "../../lib/np-tools";
|
||||
import {
|
||||
getEnglishWord,
|
||||
removeFVarients,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
|
||||
export const zIndexProps = {
|
||||
menuPortalTarget: document.body,
|
||||
styles: { menuPortal: (base: any) => ({ ...base, zIndex: 9999 }) },
|
||||
};
|
||||
|
||||
export function makeVerbSelectOption(e: VerbEntry): { value: string, label: string } {
|
||||
const eng = getEnglishVerb(e.entry);
|
||||
return {
|
||||
label: `${e.entry.p} - ${removeFVarients(e.entry.f)} ${eng ? `(${eng})` : ""}`,
|
||||
value: e.entry.ts.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeSelectOption(e: VerbEntry | NounEntry | AdjectiveEntry | LocativeAdverbEntry): { value: string, label: string } {
|
||||
const entry = "entry" in e ? e.entry : e;
|
||||
const eng = (isVerbEntry(e))
|
||||
? (getEnglishParticiple(e.entry))
|
||||
: getEnglishWord(e);
|
||||
const english = typeof eng === "string"
|
||||
? eng
|
||||
: !eng
|
||||
? ""
|
||||
: ("singular" in eng && eng.singular !== undefined)
|
||||
? eng.singular
|
||||
: eng.plural;
|
||||
return {
|
||||
label: `${entry.p} - ${removeFVarients(entry.f)} (${english})`,
|
||||
value: entry.ts.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeNounSelection(entry: NounEntry): NounSelection {
|
||||
const number = isPluralNounEntry(entry) ? "plur" : "sing";
|
||||
return {
|
||||
type: "noun",
|
||||
entry,
|
||||
gender: isMascNounEntry(entry) ? "masc" : "fem",
|
||||
number,
|
||||
...isUnisexNounEntry(entry) ? {
|
||||
changeGender: function(gender: "masc" | "fem"): NounSelection {
|
||||
return {
|
||||
...this,
|
||||
gender,
|
||||
};
|
||||
},
|
||||
} : {},
|
||||
...number === "sing" ? {
|
||||
changeNumber: function(number: "plur" | "sing"): NounSelection {
|
||||
return {
|
||||
...this,
|
||||
number,
|
||||
};
|
||||
},
|
||||
} : {},
|
||||
};
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import NPPicker from "../np-picker/NPPicker";
|
||||
|
||||
function ObjectDisplay({ object, onChange }: { object: Exclude<VerbObject, "none">, onChange: (o: NPSelection | undefined) => void }) {
|
||||
return (typeof object === "number")
|
||||
? <div className="text-muted">Unspoken 3rd Pers. Masc. Plur.</div>
|
||||
: <NPPicker np={object} onChange={onChange} />;
|
||||
}
|
||||
|
||||
export default ObjectDisplay;
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
import { useState } from "react";
|
||||
import NPPicker from "../np-picker/NPPicker";
|
||||
import VerbPicker from "../VerbPicker";
|
||||
import ObjectDisplay from "./ObjectDisplay";
|
||||
import { verbs } from "../../words/words";
|
||||
|
||||
export function PhraseBuilder() {
|
||||
const [subject, setSubject] = useState<NPSelection | undefined>(undefined);
|
||||
const [verb, setVerb] = useState<VerbSelection | undefined>(undefined);
|
||||
function handleObjectChange(object: NPSelection | undefined) {
|
||||
if (!verb) return;
|
||||
if ((verb.object === "none") || (typeof verb.object === "number")) return;
|
||||
setVerb({
|
||||
...verb,
|
||||
object,
|
||||
});
|
||||
}
|
||||
console.log({ subject, verb });
|
||||
return <div>
|
||||
<div className="d-flex flex-row justify-content-between">
|
||||
<div className="mr-2">
|
||||
<div className="h5">Subject</div>
|
||||
<NPPicker np={subject} onChange={setSubject} />
|
||||
</div>
|
||||
{verb && (verb.object !== "none") && <div className="mr-2">
|
||||
<div className="h5">Object</div>
|
||||
<ObjectDisplay object={verb.object} onChange={handleObjectChange} />
|
||||
</div>}
|
||||
<div>
|
||||
<div className="h5">Verb</div>
|
||||
<VerbPicker verbs={verbs} verb={verb} onChange={setVerb} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default PhraseBuilder;
|
|
@ -87,7 +87,7 @@ import * as games from "!babel-loader!@lingdocs/mdx-loader!./games.mdx";
|
|||
// @ts-ignore
|
||||
import * as pronounPicker from "!babel-loader!@lingdocs/mdx-loader!./practice-tools/pronoun-picker.mdx";
|
||||
// @ts-ignore
|
||||
// import * as phraseBuilder from "!babel-loader!@lingdocs/mdx-loader!./practice-tools/phrase-builder.mdx";
|
||||
import * as phraseBuilder from "!babel-loader!@lingdocs/mdx-loader!./practice-tools/phrase-builder.mdx";
|
||||
|
||||
const contentTree = [
|
||||
{
|
||||
|
@ -284,10 +284,10 @@ const contentTree = [
|
|||
import: pronounPicker,
|
||||
slug: "pronoun-picker",
|
||||
},
|
||||
// {
|
||||
// import: phraseBuilder,
|
||||
// slug: "phrase-builder",
|
||||
// },
|
||||
{
|
||||
import: phraseBuilder,
|
||||
slug: "phrase-builder",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
@ -2,17 +2,8 @@
|
|||
title: Phrase Builder
|
||||
---
|
||||
|
||||
import NPPicker from "../../components/np-picker/NPPicker";
|
||||
import { useState } from "react";
|
||||
import PhraseBuilder from "../../components/phrase-builder/PhraseBuilder";
|
||||
|
||||
export function Display() {
|
||||
const [np, setNp] = useState(undefined);
|
||||
return <div>
|
||||
<NPPicker np={np} onChange={setNp} />
|
||||
<pre>
|
||||
{JSON.stringify(np, null, " ")}
|
||||
</pre>
|
||||
</div>
|
||||
}
|
||||
This is under construction... It's not quite working yet. 👷🚧
|
||||
|
||||
<Display />
|
||||
<PhraseBuilder />
|
|
@ -145,6 +145,20 @@ function getInf(infs: T.InflectorOutput, t: "plural" | "arabicPlural" | "inflect
|
|||
return [];
|
||||
}
|
||||
|
||||
export function getEnglishVerb(entry: T.DictionaryEntry): string {
|
||||
if (!entry.ec) {
|
||||
console.log("errored verb");
|
||||
console.log(entry);
|
||||
throw new Error("no english information for verb");
|
||||
}
|
||||
if (entry.ep) {
|
||||
const ec = entry.ec.includes(",") ? parseEc(entry.ec) : entry.ec;
|
||||
return `to ${ec} ${entry.ep}`;
|
||||
}
|
||||
const ec = parseEc(entry.ec);
|
||||
return `to ${ec[0]}`;
|
||||
}
|
||||
|
||||
export function getEnglishParticiple(entry: T.DictionaryEntry): string {
|
||||
if (!entry.ec) {
|
||||
console.log("errored participle");
|
||||
|
|
|
@ -4,6 +4,28 @@
|
|||
// type FemPlurNounEntry = ""; // can change nothing
|
||||
// type UnisexNounEntry = ""; // can change number or gender
|
||||
|
||||
type VP = {
|
||||
subject: NPSelection,
|
||||
object: NPSelection,
|
||||
verb: VerbSelection,
|
||||
};
|
||||
|
||||
type VerbSelection = {
|
||||
type: "verb",
|
||||
verb: VerbEntry,
|
||||
tense: "present" | "subjunctive",
|
||||
object: VerbObject,
|
||||
};
|
||||
|
||||
type VerbObject = // intransitive verb
|
||||
"none" |
|
||||
// transitive verb - object not selected yet
|
||||
undefined |
|
||||
// transitive verb - obect selected
|
||||
NPSelection |
|
||||
// grammatically transitive verb with unspoken 3rd pers masc plur entity
|
||||
import("@lingdocs/pashto-inflector").Types.Person.ThirdPlurMale;
|
||||
|
||||
type NPSelection = NounSelection | PronounSelection | ParticipleSelection;
|
||||
|
||||
type NPType = "noun" | "pronoun" | "participle";
|
||||
|
@ -11,13 +33,7 @@ type NPType = "noun" | "pronoun" | "participle";
|
|||
// TODO require/import Person and PsString
|
||||
type NounSelection = {
|
||||
type: "noun",
|
||||
ps: import("@lingdocs/pashto-inflector").Types.PsString,
|
||||
entry: import("@lingdocs/pashto-inflector").Types.DictionaryEntry,
|
||||
// BETTER TO USE (or keep handy) FULL ENTRY FOR USE WITH INFLECTING
|
||||
e: {
|
||||
sing: string,
|
||||
plur: string,
|
||||
} | undefined,
|
||||
entry: NounEntry,
|
||||
gender: "masc" | "fem",
|
||||
number: "sing" | "plur",
|
||||
// TODO: Implement
|
||||
|
@ -33,17 +49,14 @@ type NounSelection = {
|
|||
// take an argument for subject/object in rendering English
|
||||
type PronounSelection = {
|
||||
type: "pronoun",
|
||||
e: string,
|
||||
person: import("@lingdocs/pashto-inflector").Types.Person,
|
||||
distance: "near" | "far",
|
||||
};
|
||||
|
||||
type ParticipleSelection = {
|
||||
type: "participle",
|
||||
ps: import("@lingdocs/pashto-inflector").Types.PsString,
|
||||
e: string | undefined,
|
||||
// entry in here
|
||||
}
|
||||
verb: VerbEntry,
|
||||
};
|
||||
|
||||
// not object
|
||||
// type Primitive = string | Function | number | boolean | Symbol | undefined | null;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noImplicitThis": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"noFallthroughCasesInSwitch": true
|
||||
|
|
Loading…
Reference in New Issue