more customizability on the conjugation viewer
This commit is contained in:
parent
991db5b67f
commit
a36ae0a112
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}`,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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} />
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
Loading…
Reference in New Issue