more customizability on the conjugation viewer

This commit is contained in:
lingdocs 2021-07-09 13:36:56 +03:00
parent 991db5b67f
commit a36ae0a112
9 changed files with 102 additions and 55 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@lingdocs/pashto-inflector",
"version": "0.6.9",
"version": "0.7.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",

View File

@ -7,7 +7,7 @@
*/
import { useEffect, useReducer } from "react";
import VerbInfo from "./verb-info/VerbInfo";
import VerbInfo, { RootsAndStems } from "./verb-info/VerbInfo";
import VerbFormDisplay from "./VerbFormDisplay";
import ButtonSelect from "./ButtonSelect";
import Hider from "./Hider";
@ -172,11 +172,15 @@ const initialState: State = {
formsOpened: [],
};
function ConjugationViewer({ entry, complement, textOptions, aayTailType }: {
function ConjugationViewer({ entry, complement, textOptions, aayTailType, showOnly, highlightInRootsAndStems, hidePastParticiple, sentenceLevel }: {
entry: T.DictionaryEntry,
complement?: T.DictionaryEntry,
textOptions: T.TextOptions,
aayTailType?: T.AayTail,
showOnly?: string | string[],
highlightInRootsAndStems?: T.RootsOrStemsToHighlight,
hidePastParticiple?: boolean,
sentenceLevel?: "easy" | "medium" | "hard",
}) {
const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => {
@ -223,13 +227,22 @@ function ConjugationViewer({ entry, complement, textOptions, aayTailType }: {
const filterDifficulty = (f: T.DisplayForm): boolean => (
state.difficulty === "advanced" || !f.advanced
);
const limitTo = !showOnly
? undefined
: Array.isArray(showOnly)
? showOnly
: [showOnly];
const forms = getForms({
conj: verbConj,
filterFunc: filterDifficulty,
filterFunc: [
filterDifficulty,
...limitTo ? [(f: T.DisplayForm): boolean => limitTo.includes(f.label)] : [],
],
mode: state.mode,
subject: state.subject,
object: state.object,
negative: state.negative,
sentenceLevel,
englishConjugation,
});
return <div className="mb-4">
@ -282,44 +295,57 @@ function ConjugationViewer({ entry, complement, textOptions, aayTailType }: {
/>
</div>
</div>}
<VerbInfo
info={verbConj.info}
textOptions={textOptions}
showingStemsAndRoots={state.showingStemsAndRoots}
toggleShowingSar={() => dispatch({ type: "toggle showingStemsAndRoots" })}
/>
{!limitTo ?
<VerbInfo
info={verbConj.info}
textOptions={textOptions}
showingStemsAndRoots={state.showingStemsAndRoots}
highlightInRootsAndStems={highlightInRootsAndStems}
toggleShowingSar={() => dispatch({ type: "toggle showingStemsAndRoots" })}
hidePastParticiple={hidePastParticiple}
/>
:
<RootsAndStems
textOptions={textOptions}
info={verbConj.info}
highlighted={highlightInRootsAndStems}
hidePastParticiple={hidePastParticiple}
/>
}
<div className="d-flex flex-row align-items-center justify-content-around flex-wrap mt-4 mb-2">
<div className="mb-3">
<ButtonSelect
options={[
{ label: `Charts`, value: "chart" },
{ label: `Chart${forms.length !== 1 ? "s" : ""}`, value: "chart" },
{ label: `Sentences`, value: "sentence" },
]}
value={state.mode}
handleChange={(p) => dispatch({ type: "setMode", payload: p as "chart" | "sentence" })}
/>
</div>
<div className="mb-3">
<ButtonSelect
options={[
{ label: "👶 Beginner", value: "beginner" },
{ label: "🤓 Advanced", value: "advanced" },
]}
value={state.difficulty}
handleChange={(p) => dispatch({ type: "set difficulty", payload: p as Difficulty })}
/>
</div>
<div className="form-group form-check">
<input
type="checkbox"
className="form-check-input"
checked={state.showingFormInfo}
onChange={(e) => {
dispatch({ type: "setShowingFormInfo", payload: e.target.checked })
}}
/>
<label className="form-check-label">Show Form Info</label>
</div>
{!limitTo && <>
<div className="mb-3">
<ButtonSelect
options={[
{ label: "👶 Beginner", value: "beginner" },
{ label: "🤓 Advanced", value: "advanced" },
]}
value={state.difficulty}
handleChange={(p) => dispatch({ type: "set difficulty", payload: p as Difficulty })}
/>
</div>
<div className="form-group form-check">
<input
type="checkbox"
className="form-check-input"
checked={state.showingFormInfo}
onChange={(e) => {
dispatch({ type: "setShowingFormInfo", payload: e.target.checked })
}}
/>
<label className="form-check-label">Show Form Info</label>
</div>
</>}
</div>
{state.mode === "sentence" &&
<div className="position-sticky pb-1" style={{ top: 0, background: "var(--theme-shade)", zIndex: 1000 }}>
@ -352,7 +378,7 @@ function ConjugationViewer({ entry, complement, textOptions, aayTailType }: {
state={state}
handleChange={(payload: string) => dispatch({ type: "set forms opened", payload })}
verbConj={verbConj}
textOptions={textOptions}
textOptions={textOptions}
/>
</div>;
}
@ -381,6 +407,7 @@ function FormsDisplay({ forms, state, handleChange, textOptions, verbConj }: {
aspect={"aspect" in f ? f.aspect : undefined}
showing={state.formsOpened.includes(f.label)}
handleChange={() => handleChange(f.label)}
ignore={forms.length === 1}
>
{"content" in f ?
drawLevel(f.content, level + 1)

View File

@ -27,11 +27,17 @@ function Hider(props: {
handleChange: () => void,
children: React.ReactNode,
hLevel?: number,
ignore?: boolean,
}) {
const hLev = Math.min((props.hLevel ? props.hLevel : defaultLevel), 6);
const extraMargin = (props.hLevel && (props.hLevel > indentAfterLevel))
? `ml-${(props.hLevel - indentAfterLevel) + 1}`
: "";
if (props.ignore) {
return <>
{props.children}
</>;
}
return <div className="mb-3">
{createElement(
`h${hLev}`,

View File

@ -64,7 +64,8 @@ function PersonSelection(props: {
<div className="row align-items-baseline">
<div className="col">
<label className="form-label">
<strong>{props.info.transitivity === "intransitive" ? "Subject" : "Subject/Agent"}</strong>
{/* TODO: Should I put the Subject/Agent label back in for non-transitive verbs?? */}
<strong>Subject</strong>
</label>
<PersonSelect
setting="subject"

View File

@ -30,7 +30,7 @@ const indentR = {
};
const highlight = {
background: "yellow",
background: "rgba(255, 227, 10, 0.6)",
};
const title: CSSProperties = {
@ -43,7 +43,7 @@ export function RootsAndStems({ textOptions, info, hidePastParticiple, highlight
textOptions: T.TextOptions,
info: T.NonComboVerbInfo,
hidePastParticiple?: boolean,
highlighted?: ("imperfective root" | "perfective root" | "imperfective stem" | "perfective stem" | "past participle")[],
highlighted?: T.RootsOrStemsToHighlight,
}) {
const hasPerfectiveSplit = !!(info.root.perfectiveSplit || info.stem.perfectiveSplit);
const showPersInf = hasPersInfs(info);
@ -173,11 +173,13 @@ export function RootsAndStems({ textOptions, info, hidePastParticiple, highlight
);
}
function VerbInfo({ info, textOptions, showingStemsAndRoots, toggleShowingSar }: {
function VerbInfo({ info, textOptions, showingStemsAndRoots, toggleShowingSar, highlightInRootsAndStems, hidePastParticiple }: {
info: T.NonComboVerbInfo,
textOptions: T.TextOptions,
showingStemsAndRoots: boolean,
highlightInRootsAndStems?: T.RootsOrStemsToHighlight,
toggleShowingSar: () => void,
hidePastParticiple?: boolean,
}) {
const inf = noPersInfs(info.root.imperfective).long;
return (
@ -195,6 +197,8 @@ function VerbInfo({ info, textOptions, showingStemsAndRoots, toggleShowingSar }:
<RootsAndStems
textOptions={textOptions}
info={info}
highlighted={highlightInRootsAndStems}
hidePastParticiple={hidePastParticiple}
/>
</Hider>
</div>

View File

@ -254,17 +254,17 @@ function VerbTypeInfo({ info, textOptions }: {
<div className="text-center my-2">
This is a
<button
className="btn btn-light mx-2 my-1"
className="btn btn-sm btn-light mx-2 my-1"
onClick={() => setShowingTypeModal(true)}
>
<strong>{info.type}</strong> <i className={`fa fa-question-circle`}></i>
<strong>{info.type}</strong>
</button>
verb and it's
<button
className="btn btn-light mx-2 my-1"
className="btn btn-sm btn-light mx-2 my-1"
onClick={() => setShowingTransModal(true)}
>
<strong>{info.transitivity}</strong> <i className={`fa fa-question-circle`}></i>
<strong>{info.transitivity}</strong>
</button>
</div>
<CompoundBreakdown info={info} textOptions={textOptions} />

View File

@ -63,7 +63,7 @@ type Pronouns = undefined | {
const nuParticle = { p: "نه", f: "nú" };
export default function addPronouns({ s, subject, object, info, displayForm, intransitive, ergative, matrixKey, englishConjugation, negative }: {
export default function addPronouns({ s, subject, object, info, displayForm, intransitive, ergative, matrixKey, englishConjugation, negative, sentenceLevel = "hard" }: {
s: T.SentenceForm,
subject: T.Person,
object: T.Person,
@ -74,13 +74,14 @@ export default function addPronouns({ s, subject, object, info, displayForm, int
matrixKey: T.PersonInflectionsField,
negative: boolean,
englishConjugation?: T.EnglishVerbConjugation,
sentenceLevel?: "easy" | "medium" | "hard",
}): T.SentenceForm {
if ("long" in s) {
return {
long: addPronouns({ s: s.long, subject, object, info, displayForm, intransitive, ergative, matrixKey, englishConjugation, negative }) as T.ArrayOneOrMore<T.PsString>,
short: addPronouns({ s: s.short, subject, object, info, displayForm, intransitive, ergative, matrixKey, englishConjugation, negative }) as T.ArrayOneOrMore<T.PsString>,
long: addPronouns({ s: s.long, subject, object, info, displayForm, intransitive, ergative, matrixKey, englishConjugation, negative, sentenceLevel }) as T.ArrayOneOrMore<T.PsString>,
short: addPronouns({ s: s.short, subject, object, info, displayForm, intransitive, ergative, matrixKey, englishConjugation, negative, sentenceLevel }) as T.ArrayOneOrMore<T.PsString>,
...s.mini ? {
mini: addPronouns({ s: s.mini, subject, object, info, displayForm, intransitive, ergative, matrixKey, englishConjugation, negative }) as T.ArrayOneOrMore<T.PsString>,
mini: addPronouns({ s: s.mini, subject, object, info, displayForm, intransitive, ergative, matrixKey, englishConjugation, negative, sentenceLevel }) as T.ArrayOneOrMore<T.PsString>,
} : {},
}
}
@ -126,11 +127,11 @@ export default function addPronouns({ s, subject, object, info, displayForm, int
? undefined
: noObjectPronoun
? {
subject: nearPronounPossible(subject) ? [subjectPronoun, nearSubjectPronoun] : subjectPronoun,
subject: ((sentenceLevel === "hard") && nearPronounPossible(subject)) ? [subjectPronoun, nearSubjectPronoun] : subjectPronoun,
mini: miniPronoun,
} : {
subject: nearPronounPossible(subject) ? [subjectPronoun, nearSubjectPronoun] : subjectPronoun,
object: nearPronounPossible(object) ? [objectPronoun, nearObjectPronoun] : objectPronoun,
subject: ((sentenceLevel === "hard") && nearPronounPossible(subject)) ? [subjectPronoun, nearSubjectPronoun] : subjectPronoun,
object: ((sentenceLevel === "hard") && nearPronounPossible(object)) ? [objectPronoun, nearObjectPronoun] : objectPronoun,
mini: miniPronoun,
};
const english = (displayForm.englishBuilder && englishConjugation)
@ -163,7 +164,7 @@ export default function addPronouns({ s, subject, object, info, displayForm, int
// basic form two full pronouns
...makeBasicPronounForm(ps, splitHead, displayForm, info, negative, prns.subject, prns.object),
// basic form one full, one mini pronoun
...makeBasicPronounForm(
...sentenceLevel !== "easy" ? makeBasicPronounForm(
ps,
splitHead,
displayForm,
@ -171,7 +172,7 @@ export default function addPronouns({ s, subject, object, info, displayForm, int
negative,
ergative ? prns.object : prns.subject,
prns.mini,
),
) : [],
] as T.ArrayOneOrMore<T.PsString>;
const ergativeGrammTrans = (info.transitivity === "grammatically transitive" && ergative);
@ -179,7 +180,7 @@ export default function addPronouns({ s, subject, object, info, displayForm, int
|| transDynCompPast || ergativeGrammTrans;
return [
...basicForms,
...canWorkWithOnlyMini
...(sentenceLevel !== "easy" && canWorkWithOnlyMini)
? makeOnlyMiniForm(ps, splitHead, displayForm, info, negative, prns.mini)
: [],
].map((ps) => english ? { ...ps, e: english } : ps) as T.ArrayOneOrMore<T.PsString>;

View File

@ -40,6 +40,7 @@ type MapFunc = (opts: {
info: T.NonComboVerbInfo,
negative: boolean,
englishConjugation?: T.EnglishVerbConjugation,
sentenceLevel?: "easy" | "medium" | "hard",
}) => T.DisplayFormItem;
/**
@ -87,20 +88,22 @@ const formMap = (
object: T.Person,
negative: boolean,
englishConjugation?: T.EnglishVerbConjugation,
sentenceLevel?: "easy" | "medium" | "hard",
): T.DisplayFormItem[] => {
return input.map((f) => (
"content" in f
? { ...f, content: formMap(f.content, func, info, subject, object, negative, englishConjugation) }
: func({ displayForm: f as T.DisplayFormForSentence, info, subject, object, negative, englishConjugation })
? { ...f, content: formMap(f.content, func, info, subject, object, negative, englishConjugation, sentenceLevel) }
: func({ displayForm: f as T.DisplayFormForSentence, info, subject, object, negative, englishConjugation, sentenceLevel })
));
};
const makeSentence = ({ subject, object, info, displayForm, englishConjugation, negative }: {
const makeSentence = ({ subject, object, info, displayForm, englishConjugation, negative, sentenceLevel }: {
subject: T.Person,
object: T.Person,
info: T.NonComboVerbInfo,
displayForm: T.DisplayFormForSentence,
negative: boolean,
sentenceLevel?: "easy" | "medium" | "hard",
englishConjugation?: T.EnglishVerbConjugation,
}): T.DisplayForm => {
const intransitive = info.transitivity === "intransitive" || !!displayForm.passive;
@ -127,6 +130,7 @@ const makeSentence = ({ subject, object, info, displayForm, englishConjugation,
matrixKey,
negative,
englishConjugation,
sentenceLevel,
});
return {
...displayForm,
@ -641,13 +645,14 @@ const formsOfConjugation = (conj: T.VerbConjugation): T.DisplayFormItem[] => [
: [],
];
export const getForms = ({ conj, filterFunc, mode, subject, object, englishConjugation, negative } : {
export const getForms = ({ conj, filterFunc, mode, subject, object, sentenceLevel, englishConjugation, negative } : {
conj: T.VerbConjugation,
englishConjugation?: T.EnglishVerbConjugation
filterFunc?: FilterFunc | FilterFunc[],
mode: "chart" | "sentence",
subject: T.Person,
object: T.Person,
sentenceLevel?: "easy" | "medium" | "hard",
negative: boolean,
}): T.DisplayFormItem[] => {
const forms = formsOfConjugation(conj);
@ -665,6 +670,7 @@ export const getForms = ({ conj, filterFunc, mode, subject, object, englishConju
object,
negative,
englishConjugation,
sentenceLevel,
);
}

View File

@ -389,6 +389,8 @@ export type ArrayOneOrMore<T> = {
0: T
} & Array<T>
export type RootsOrStemsToHighlight = ("imperfective root" | "perfective root" | "imperfective stem" | "perfective stem" | "past participle")[];
/* i.e. ec: ["take", "takes", "taking", "took", "taken"], ep: out */
export type EnglishVerbConjugationEc = [string, string, string, string, string];
export type EnglishVerbConjugation = {