ok getting better!
This commit is contained in:
parent
1bc735d809
commit
221362745f
|
@ -0,0 +1,180 @@
|
||||||
|
import Select from "react-select";
|
||||||
|
import {
|
||||||
|
zIndexProps,
|
||||||
|
} from "./np-picker/picker-tools";
|
||||||
|
import {
|
||||||
|
ButtonSelect,
|
||||||
|
} from "@lingdocs/pashto-inflector";
|
||||||
|
import { isPerfectTense } from "../lib/phrase-building/vp-tools";
|
||||||
|
|
||||||
|
const tenseOptions: { label: string | JSX.Element, value: VerbTense }[] = [{
|
||||||
|
label: <div><i className="fas fa-video mr-2" />present</div>,
|
||||||
|
value: "presentVerb",
|
||||||
|
}, {
|
||||||
|
label: <div><i className="fas fa-camera mr-2" />subjunctive</div>,
|
||||||
|
value: "subjunctiveVerb",
|
||||||
|
}, {
|
||||||
|
label: <div><i className="fas fa-video mr-2" />imperf. future</div>,
|
||||||
|
value: "imperfectiveFuture",
|
||||||
|
}, {
|
||||||
|
label: <div><i className="fas fa-camera mr-2" />perf. future</div>,
|
||||||
|
value: "perfectiveFuture",
|
||||||
|
}, {
|
||||||
|
label: <div><i className="fas fa-video mr-2" />continuous past</div>,
|
||||||
|
value: "imperfectivePast",
|
||||||
|
}, {
|
||||||
|
label: <div><i className="fas fa-camera mr-2" />simple past</div>,
|
||||||
|
value: "perfectivePast",
|
||||||
|
}, {
|
||||||
|
label: <div><i className="fas fa-video mr-2" />habitual cont. past</div>,
|
||||||
|
value: "habitualImperfectivePast",
|
||||||
|
}, {
|
||||||
|
label: <div><i className="fas fa-camera mr-2" />habitual simp. past</div>,
|
||||||
|
value: "habitualPerfectivePast",
|
||||||
|
}];
|
||||||
|
|
||||||
|
const perfectTenseOptions: { label: string | JSX.Element, value: PerfectTense }[] = [{
|
||||||
|
label: "Present Perfect",
|
||||||
|
value: "present perfect",
|
||||||
|
}, {
|
||||||
|
label: "Habitual Perfect",
|
||||||
|
value: "habitual perfect",
|
||||||
|
}, {
|
||||||
|
label: "Subjunctive Perfect",
|
||||||
|
value: "subjunctive perfect",
|
||||||
|
}, {
|
||||||
|
label: "Future Perfect",
|
||||||
|
value: "future perfect",
|
||||||
|
}, {
|
||||||
|
label: "Past Perfect",
|
||||||
|
value: "past perfect",
|
||||||
|
}, {
|
||||||
|
label: `"Would Be" Perfect`,
|
||||||
|
value: "wouldBe perfect",
|
||||||
|
}, {
|
||||||
|
label: "Past Subjunctive Perfect",
|
||||||
|
value: "pastSubjunctive perfect",
|
||||||
|
}];
|
||||||
|
|
||||||
|
function TensePicker({ onChange, verb, mode }: {
|
||||||
|
verbs: VerbEntry[],
|
||||||
|
verb: VerbSelection | undefined,
|
||||||
|
onChange: (p: VerbSelection | undefined) => void,
|
||||||
|
mode: "charts" | "phrases",
|
||||||
|
}) {
|
||||||
|
function onTenseSelect(o: { value: VerbTense | PerfectTense } | null) {
|
||||||
|
const value = o?.value ? o.value : undefined;
|
||||||
|
if (verb && value) {
|
||||||
|
if (isPerfectTense(value)) {
|
||||||
|
onChange({
|
||||||
|
...verb,
|
||||||
|
tense: value,
|
||||||
|
tenseCategory: "perfect",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onChange({
|
||||||
|
...verb,
|
||||||
|
tense: value,
|
||||||
|
tenseCategory: verb.tenseCategory === "perfect" ? "basic" : verb.tenseCategory,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function moveTense(dir: "forward" | "back") {
|
||||||
|
if (!verb) return;
|
||||||
|
return () => {
|
||||||
|
const tenses = verb.tenseCategory === "perfect" ? perfectTenseOptions : tenseOptions;
|
||||||
|
const currIndex = tenses.findIndex(tn => tn.value === verb.tense)
|
||||||
|
if (currIndex === -1) {
|
||||||
|
console.error("error moving tense", dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const newIndex = dir === "forward"
|
||||||
|
? ((currIndex + 1) % tenses.length)
|
||||||
|
: (currIndex === 0 ? (tenses.length - 1) : (currIndex - 1))
|
||||||
|
const newTense = tenses[newIndex];
|
||||||
|
onTenseSelect(newTense);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function onPosNegSelect(value: string) {
|
||||||
|
if (verb) {
|
||||||
|
onChange({
|
||||||
|
...verb,
|
||||||
|
negative: value === "true",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function onTenseCategorySelect(value: "basic" | "modal" | "perfect") {
|
||||||
|
if (verb) {
|
||||||
|
if (value === "perfect") {
|
||||||
|
onChange({
|
||||||
|
...verb,
|
||||||
|
tenseCategory: value,
|
||||||
|
tense: isPerfectTense(verb.tense) ? verb.tense : "present perfect",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onChange({
|
||||||
|
...verb,
|
||||||
|
tenseCategory: value,
|
||||||
|
tense: isPerfectTense(verb.tense) ? "presentVerb" : verb.tense,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const tOptions = (verb?.tenseCategory === "perfect") ? perfectTenseOptions : tenseOptions;
|
||||||
|
return <div className="mb-0 mt-3">
|
||||||
|
<div style={{ maxWidth: "300px", minWidth: "250px", margin: "0 auto" }}>
|
||||||
|
<div className="d-flex flex-row justify-content-between align-items-center">
|
||||||
|
<div className="h5">Tense:</div>
|
||||||
|
{verb && <div className="mb-2">
|
||||||
|
<ButtonSelect
|
||||||
|
small
|
||||||
|
value={verb.tenseCategory}
|
||||||
|
options={[{
|
||||||
|
label: "Basic",
|
||||||
|
value: "basic",
|
||||||
|
}, {
|
||||||
|
label: "Perfect",
|
||||||
|
value: "perfect",
|
||||||
|
}, {
|
||||||
|
label: "Modal",
|
||||||
|
value: "modal",
|
||||||
|
}]}
|
||||||
|
handleChange={onTenseCategorySelect}
|
||||||
|
/>
|
||||||
|
</div>}
|
||||||
|
</div>
|
||||||
|
<Select
|
||||||
|
isSearchable={false}
|
||||||
|
// for some reason can't use tOptions with find here;
|
||||||
|
value={verb && ([...tenseOptions, ...perfectTenseOptions].find(o => o.value === verb.tense))}
|
||||||
|
onChange={onTenseSelect}
|
||||||
|
className="mb-2"
|
||||||
|
options={tOptions}
|
||||||
|
{...zIndexProps}
|
||||||
|
/>
|
||||||
|
{verb && <div className="d-flex flex-row justify-content-between align-items-center mt-3 mb-1" style={{ width: "100%" }}>
|
||||||
|
<div onClick={moveTense("back")} className="clickable">
|
||||||
|
<i className="fas fa-chevron-left" />
|
||||||
|
</div>
|
||||||
|
{mode !== "charts" && <ButtonSelect
|
||||||
|
small
|
||||||
|
value={verb.negative.toString()}
|
||||||
|
options={[{
|
||||||
|
label: "Pos.",
|
||||||
|
value: "false",
|
||||||
|
}, {
|
||||||
|
label: "Neg.",
|
||||||
|
value: "true",
|
||||||
|
}]}
|
||||||
|
handleChange={onPosNegSelect}
|
||||||
|
/>}
|
||||||
|
<div onClick={moveTense("forward")} className="clickable">
|
||||||
|
<i className="fas fa-chevron-right" />
|
||||||
|
</div>
|
||||||
|
</div>}
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TensePicker;
|
|
@ -1,22 +1,32 @@
|
||||||
import {
|
import {
|
||||||
ButtonSelect,
|
ButtonSelect,
|
||||||
Types as T,
|
Types as T,
|
||||||
|
RootsAndStems,
|
||||||
|
getVerbInfo,
|
||||||
} from "@lingdocs/pashto-inflector";
|
} from "@lingdocs/pashto-inflector";
|
||||||
|
import Hider from "@lingdocs/pashto-inflector/dist/components/Hider";
|
||||||
import {
|
import {
|
||||||
makeVerbSelection,
|
makeVerbSelection,
|
||||||
} from "./phrase-builder/verb-selection";
|
} from "./phrase-builder/verb-selection";
|
||||||
import EntrySelect from "./EntrySelect";
|
import EntrySelect from "./EntrySelect";
|
||||||
|
import useStickyState from "../useStickyState";
|
||||||
|
|
||||||
// TODO: dark on past tense selecitons
|
// TODO: dark on past tense selecitons
|
||||||
|
|
||||||
function VerbPicker({ onChange, subject, changeSubject, verb, verbs, opts }: {
|
function VerbPicker({ onChange, subject, changeSubject, verb, verbs, opts, verbLocked }: {
|
||||||
verbs: VerbEntry[],
|
verbs: VerbEntry[],
|
||||||
verb: VerbSelection | undefined,
|
verb: VerbSelection | undefined,
|
||||||
subject: NPSelection | undefined,
|
subject: NPSelection | undefined,
|
||||||
onChange: (p: VerbSelection | undefined) => void,
|
onChange: (p: VerbSelection | undefined) => void,
|
||||||
changeSubject: (p: NPSelection | undefined) => void,
|
changeSubject: (p: NPSelection | undefined) => void,
|
||||||
opts: T.TextOptions,
|
opts: T.TextOptions,
|
||||||
|
verbLocked: boolean,
|
||||||
}) {
|
}) {
|
||||||
|
const [showRootsAndStems, setShowRootsAndStems] = useStickyState<boolean>(false, "showRootsAndStems");
|
||||||
|
const info = verb ? getVerbInfo(verb.verb.entry, verb.verb.complement) : undefined;
|
||||||
|
if (info && ("stative" in info || "transitive" in info)) {
|
||||||
|
return <div>ERROR: Verb version should be select first</div>;
|
||||||
|
}
|
||||||
// const [filters, useFilters] = useState<Filters>({
|
// const [filters, useFilters] = useState<Filters>({
|
||||||
// stative: true,
|
// stative: true,
|
||||||
// dynamic: true,
|
// dynamic: true,
|
||||||
|
@ -56,7 +66,7 @@ function VerbPicker({ onChange, subject, changeSubject, verb, verbs, opts }: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return <div className="mb-3">
|
return <div className="mb-3">
|
||||||
<div style={{ maxWidth: "300px", margin: "0 auto" }}>
|
{!verbLocked && <div style={{ maxWidth: "300px", margin: "0 auto" }}>
|
||||||
<div className="h5">Verb:</div>
|
<div className="h5">Verb:</div>
|
||||||
<EntrySelect
|
<EntrySelect
|
||||||
entries={verbs}
|
entries={verbs}
|
||||||
|
@ -66,7 +76,20 @@ function VerbPicker({ onChange, subject, changeSubject, verb, verbs, opts }: {
|
||||||
isVerbSelect
|
isVerbSelect
|
||||||
opts={opts}
|
opts={opts}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>}
|
||||||
|
{info && <div className="mt-3 mb-1 text-center">
|
||||||
|
<Hider
|
||||||
|
showing={showRootsAndStems}
|
||||||
|
label="🌳 Roots and Stems"
|
||||||
|
handleChange={() => setShowRootsAndStems(p => !p)}
|
||||||
|
hLevel={5}
|
||||||
|
>
|
||||||
|
<RootsAndStems
|
||||||
|
textOptions={opts}
|
||||||
|
info={info}
|
||||||
|
/>
|
||||||
|
</Hider>
|
||||||
|
</div>}
|
||||||
<div className="d-flex flex-row justify-content-around flex-wrap" style={{ maxWidth: "400px", margin: "0 auto" }}>
|
<div className="d-flex flex-row justify-content-around flex-wrap" style={{ maxWidth: "400px", margin: "0 auto" }}>
|
||||||
{verb && verb.changeTransitivity && <div className="text-center my-2">
|
{verb && verb.changeTransitivity && <div className="text-center my-2">
|
||||||
<ButtonSelect
|
<ButtonSelect
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
import {
|
||||||
|
isPluralNounEntry,
|
||||||
|
isMascNounEntry,
|
||||||
|
isUnisexNounEntry,
|
||||||
|
isVerbEntry,
|
||||||
|
} from "../../lib/type-predicates";
|
||||||
|
import {
|
||||||
|
getEnglishParticiple,
|
||||||
|
getEnglishVerb,
|
||||||
|
} from "../../lib/np-tools";
|
||||||
|
import {
|
||||||
|
getEnglishWord,
|
||||||
|
removeFVarients,
|
||||||
|
Types as T,
|
||||||
|
InlinePs,
|
||||||
|
} from "@lingdocs/pashto-inflector";
|
||||||
|
|
||||||
|
export const zIndexProps = {
|
||||||
|
menuPortalTarget: document.body,
|
||||||
|
styles: { menuPortal: (base: any) => ({ ...base, zIndex: 9999 }) },
|
||||||
|
};
|
||||||
|
|
||||||
|
export function makeVerbSelectOption(e: VerbEntry, opts: T.TextOptions): { value: string, label: string | JSX.Element } {
|
||||||
|
const eng = getEnglishVerb(e.entry);
|
||||||
|
return {
|
||||||
|
label: <InlinePs opts={opts}>
|
||||||
|
{{ p: e.entry.p, f: removeFVarients(e.entry.f), e: eng }}
|
||||||
|
</InlinePs>,
|
||||||
|
value: e.entry.ts.toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeSelectOption(
|
||||||
|
e: T.DictionaryEntry | VerbEntry | NounEntry | AdjectiveEntry | LocativeAdverbEntry,
|
||||||
|
opts: T.TextOptions,
|
||||||
|
): { value: string, label: JSX.Element | 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: <InlinePs opts={opts}>
|
||||||
|
{{ p: entry.p, f: removeFVarients(entry.f), e: english }}
|
||||||
|
</InlinePs>,
|
||||||
|
value: entry.ts.toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeNounSelection(entry: NounEntry, dynamicComplement?: true): NounSelection {
|
||||||
|
const number = isPluralNounEntry(entry) ? "plural" : "singular";
|
||||||
|
return {
|
||||||
|
type: "noun",
|
||||||
|
entry,
|
||||||
|
gender: isMascNounEntry(entry) ? "masc" : "fem",
|
||||||
|
number,
|
||||||
|
dynamicComplement,
|
||||||
|
...isUnisexNounEntry(entry) ? {
|
||||||
|
changeGender: function(gender: T.Gender): NounSelection {
|
||||||
|
return {
|
||||||
|
...this,
|
||||||
|
gender,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
} : {},
|
||||||
|
...number === "singular" ? {
|
||||||
|
changeNumber: function(number: NounNumber): NounSelection {
|
||||||
|
return {
|
||||||
|
...this,
|
||||||
|
number,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
} : {},
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
import {
|
||||||
|
conjugateVerb,
|
||||||
|
VerbFormDisplay,
|
||||||
|
Types as T,
|
||||||
|
} from "@lingdocs/pashto-inflector";
|
||||||
|
import {
|
||||||
|
getTenseVerbForm,
|
||||||
|
} from "../../lib/phrase-building/vp-tools";
|
||||||
|
|
||||||
|
function ChartDisplay({ VS, opts }: { VS: VerbSelection, opts: T.TextOptions }) {
|
||||||
|
const conjugations = conjugateVerb(VS.verb.entry, VS.verb.complement);
|
||||||
|
if (!conjugations) {
|
||||||
|
return <div>Error conjugating verb</div>;
|
||||||
|
}
|
||||||
|
if ("stative" in conjugations || "transitive" in conjugations) {
|
||||||
|
return <div>Error: compound or transitivity type should be selected first</div>;
|
||||||
|
}
|
||||||
|
const form = getTenseVerbForm(conjugations, VS.tense, VS.tenseCategory, VS.voice);
|
||||||
|
return <div className="mb-4">
|
||||||
|
<VerbFormDisplay
|
||||||
|
displayForm={form}
|
||||||
|
showingFormInfo={false}
|
||||||
|
textOptions={opts}
|
||||||
|
info={conjugations.info}
|
||||||
|
/>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChartDisplay;
|
|
@ -14,6 +14,8 @@ import {
|
||||||
Types as T,
|
Types as T,
|
||||||
} from "@lingdocs/pashto-inflector";
|
} from "@lingdocs/pashto-inflector";
|
||||||
import ChartDisplay from "./ChartDisplay";
|
import ChartDisplay from "./ChartDisplay";
|
||||||
|
import useStickyState from "../../useStickyState";
|
||||||
|
import { makeVerbSelection } from "./verb-selection";
|
||||||
|
|
||||||
const kingEmoji = "👑";
|
const kingEmoji = "👑";
|
||||||
const servantEmoji = "🙇♂️";
|
const servantEmoji = "🙇♂️";
|
||||||
|
@ -34,9 +36,11 @@ export function PhraseBuilder(props: {
|
||||||
verb?: VerbEntry,
|
verb?: VerbEntry,
|
||||||
opts?: T.TextOptions,
|
opts?: T.TextOptions,
|
||||||
}) {
|
}) {
|
||||||
const [subject, setSubject] = useState<NPSelection | undefined>(undefined);
|
const [subject, setSubject] = useStickyState<NPSelection | undefined>(undefined, "subjectNPSelection");
|
||||||
const [mode, setMode] = useState<"charts" | "phrases">("phrases");
|
const [mode, setMode] = useStickyState<"charts" | "phrases">("phrases", "verbExplorerMode");
|
||||||
const [verb, setVerb] = useState<VerbSelection | undefined>(undefined);
|
const [verb, setVerb] = useState<VerbSelection | undefined>(
|
||||||
|
props.verb ? makeVerbSelection(props.verb, setSubject, undefined) : undefined,
|
||||||
|
);
|
||||||
const textOpts = props.opts || defaultTextOptions;
|
const textOpts = props.opts || defaultTextOptions;
|
||||||
function handleSubjectChange(subject: NPSelection | undefined, skipPronounConflictCheck?: boolean) {
|
function handleSubjectChange(subject: NPSelection | undefined, skipPronounConflictCheck?: boolean) {
|
||||||
if (!skipPronounConflictCheck && hasPronounConflict(subject, verb?.object)) {
|
if (!skipPronounConflictCheck && hasPronounConflict(subject, verb?.object)) {
|
||||||
|
@ -69,6 +73,7 @@ export function PhraseBuilder(props: {
|
||||||
<div>{servantEmoji} = <abbr title="can be shrunken into a mini-pronoun">servant</abbr> of phrase</div>
|
<div>{servantEmoji} = <abbr title="can be shrunken into a mini-pronoun">servant</abbr> of phrase</div>
|
||||||
</div>
|
</div>
|
||||||
<VerbPicker
|
<VerbPicker
|
||||||
|
verbLocked={!!props.verb}
|
||||||
verbs={verbs}
|
verbs={verbs}
|
||||||
verb={verb}
|
verb={verb}
|
||||||
subject={subject}
|
subject={subject}
|
||||||
|
@ -86,7 +91,7 @@ export function PhraseBuilder(props: {
|
||||||
handleChange={setMode}
|
handleChange={setMode}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{(verb && (typeof verb.object === "object") && (verb.isCompound !== "dynamic")) &&
|
{(verb && (typeof verb.object === "object") && (verb.isCompound !== "dynamic") && (mode !== "charts")) &&
|
||||||
<div className="text-center mt-4">
|
<div className="text-center mt-4">
|
||||||
<button onClick={handleSubjObjSwap} className="btn btn-sm btn-light">
|
<button onClick={handleSubjObjSwap} className="btn btn-sm btn-light">
|
||||||
<i className="fas fa-exchange-alt mr-2" /> subj/obj
|
<i className="fas fa-exchange-alt mr-2" /> subj/obj
|
||||||
|
|
Loading…
Reference in New Issue