better UI and fixed bug being able to close the imperative subject

This commit is contained in:
lingdocs 2022-04-20 22:24:23 +05:00
parent 10532cb3bb
commit 611f5defe5
9 changed files with 36 additions and 45 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@lingdocs/pashto-inflector", "name": "@lingdocs/pashto-inflector",
"version": "2.1.3", "version": "2.1.4",
"author": "lingdocs.com", "author": "lingdocs.com",
"description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations", "description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations",
"homepage": "https://verbs.lingdocs.com", "homepage": "https://verbs.lingdocs.com",

View File

@ -27,14 +27,16 @@ function Examples({
children, children,
ex, ex,
opts, opts,
lineHeight,
}: { }: {
ex?: PsStringWSub | PsStringWSub[] | T.PsJSX | T.PsJSX[], ex?: PsStringWSub | PsStringWSub[] | T.PsJSX | T.PsJSX[],
children: PsStringWSub | PsStringWSub[], children: PsStringWSub | PsStringWSub[],
opts: T.TextOptions, opts: T.TextOptions,
lineHeight?: 0 | 1 | 2 | 3 | 4,
}) { }) {
const examples = children || ex; const examples = children || ex;
const Example = ({ children: text }: { children: PsStringWSub }) => ( const Example = ({ children: text }: { children: PsStringWSub }) => (
<div className="mt-1 mb-3"> <div className={lineHeight !== undefined ? `mb-${lineHeight}` : `mt-1 mb-3`}>
<div> <div>
<Pashto opts={opts}>{text}</Pashto> <Pashto opts={opts}>{text}</Pashto>
</div> </div>

View File

@ -63,7 +63,6 @@ function NPNounPicker(props: ({
}) & { }) & {
noun: T.NounSelection | undefined, noun: T.NounSelection | undefined,
onChange: (p: T.NounSelection | undefined) => void, onChange: (p: T.NounSelection | undefined) => void,
clearButton?: JSX.Element,
opts: T.TextOptions, opts: T.TextOptions,
}) { }) {
// const [patternFilter, setPatternFilter] = useState<FilterPattern | undefined>(undefined); // const [patternFilter, setPatternFilter] = useState<FilterPattern | undefined>(undefined);
@ -82,14 +81,6 @@ function NPNounPicker(props: ({
// setShowFilter(false); // setShowFilter(false);
// } // }
return <div style={{ maxWidth: "225px", minWidth: "125px" }}> return <div style={{ maxWidth: "225px", minWidth: "125px" }}>
<div className="d-flex flex-row justify-content-left">
{props.clearButton}
{/* {(!showFilter && !(noun?.dynamicComplement)) && <div className="text-right">
<button className="btn btn-sm btn-light mb-2 text-small" onClick={() => setShowFilter(true)}>
<i className="fas fa-filter fa-xs" />
</button>
</div>} */}
</div>
{/* {showFilter && <div className="mb-2 text-center"> {/* {showFilter && <div className="mb-2 text-center">
<div className="d-flex flex-row justify-content-between"> <div className="d-flex flex-row justify-content-between">
<div className="text-small mb-1">Filter by inflection pattern</div> <div className="text-small mb-1">Filter by inflection pattern</div>

View File

@ -16,7 +16,6 @@ function NPParticiplePicker(props: ({
}) & { }) & {
participle: T.ParticipleSelection | undefined, participle: T.ParticipleSelection | undefined,
onChange: (p: T.ParticipleSelection | undefined) => void, onChange: (p: T.ParticipleSelection | undefined) => void,
clearButton: JSX.Element,
opts: T.TextOptions, opts: T.TextOptions,
}) { }) {
function onEntrySelect(entry: T.VerbEntry | undefined) { function onEntrySelect(entry: T.VerbEntry | undefined) {
@ -27,7 +26,6 @@ function NPParticiplePicker(props: ({
props.onChange(makeParticipleSelection(entry)); props.onChange(makeParticipleSelection(entry));
} }
return <div style={{ maxWidth: "225px" }}> return <div style={{ maxWidth: "225px" }}>
{props.clearButton}
<h6>Participle</h6> <h6>Participle</h6>
<EntrySelect <EntrySelect
value={props.participle?.verb} value={props.participle?.verb}

View File

@ -14,6 +14,7 @@ import { isSecondPerson } from "../../lib/phrase-building/vp-tools";
const npTypes: T.NPType[] = ["pronoun", "noun", "participle"]; const npTypes: T.NPType[] = ["pronoun", "noun", "participle"];
function NPPicker(props: { function NPPicker(props: {
heading?: JSX.Element,
onChange: (nps: T.NPSelection | undefined) => void, onChange: (nps: T.NPSelection | undefined) => void,
np: T.NPSelection | undefined, np: T.NPSelection | undefined,
counterPart: T.NPSelection | T.VerbObject | undefined, counterPart: T.NPSelection | T.VerbObject | undefined,
@ -58,11 +59,21 @@ function NPPicker(props: {
} }
} }
const isDynamicComplement = props.np && props.np.type === "noun" && props.np.dynamicComplement; const isDynamicComplement = props.np && props.np.type === "noun" && props.np.dynamicComplement;
const clearButton = !props.cantClear const clearButton = (!props.cantClear && !props.is2ndPersonPicker && !isDynamicComplement)
? <button className="btn btn-sm btn-light mb-2" onClick={handleClear}>X</button> ? <button className="btn btn-sm btn-light mb-2" onClick={handleClear}>X</button>
: <div></div>; : <div></div>;
return <div style={{ minWidth: "9rem" }}> return <>
{!npType && <div className="text-center mt-3"> <div className="d-flex flex-row justify-content-between">
<div></div>
<div>
{props.heading}
</div>
<div>
{npType && clearButton}
</div>
</div>
<div style={{ minWidth: "9rem" }}>
{!npType && <div className="text-center">
<div className="h6 mr-3"> <div className="h6 mr-3">
Choose NP Choose NP
</div> </div>
@ -82,7 +93,6 @@ function NPPicker(props: {
asObject={props.asObject} asObject={props.asObject}
pronoun={props.np} pronoun={props.np}
onChange={props.onChange} onChange={props.onChange}
clearButton={clearButton}
is2ndPersonPicker={props.is2ndPersonPicker} is2ndPersonPicker={props.is2ndPersonPicker}
opts={props.opts} opts={props.opts}
/> />
@ -96,7 +106,6 @@ function NPPicker(props: {
}} }}
noun={(props.np && props.np.type === "noun") ? props.np : undefined} noun={(props.np && props.np.type === "noun") ? props.np : undefined}
onChange={props.onChange} onChange={props.onChange}
clearButton={!isDynamicComplement ? clearButton : undefined}
opts={props.opts} opts={props.opts}
/> />
: npType === "participle" : npType === "participle"
@ -109,12 +118,12 @@ function NPPicker(props: {
}} }}
participle={(props.np && props.np.type === "participle") ? props.np : undefined} participle={(props.np && props.np.type === "participle") ? props.np : undefined}
onChange={props.onChange} onChange={props.onChange}
clearButton={clearButton}
opts={props.opts} opts={props.opts}
/> />
: null : null
} }
</div>; </div>
</>;
} }
// {(npType && !isDynamicComplement) && } // {(npType && !isDynamicComplement) && }

View File

@ -103,8 +103,7 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts, is2nd
? [pSpecA[1]] ? [pSpecA[1]]
: pSpecA; : pSpecA;
return <div style={{ maxWidth: "145px", padding: 0 }}> return <div style={{ maxWidth: "145px", padding: 0 }}>
{clearButton} <div className="d-flex flex-row justify-content-between mb-2">
<div className="d-flex flex-row justify-content-between mb-3">
{isThirdPerson(pronoun.person) ? <ButtonSelect {isThirdPerson(pronoun.person) ? <ButtonSelect
xSmall xSmall
options={[ options={[
@ -133,7 +132,7 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts, is2nd
className={classNames({ "table-active": active, "text-on-gender-color": active })} className={classNames({ "table-active": active, "text-on-gender-color": active })}
style={{ style={{
backgroundColor: active ? gColors[p.gender] : "inherit", backgroundColor: active ? gColors[p.gender] : "inherit",
padding: "0.25rem 0", padding: "0.15rem 0",
}} }}
> >
<div className="my-1"> <div className="my-1">

View File

@ -57,10 +57,10 @@ const perfectTenseOptions: { label: string | JSX.Element, value: T.PerfectTense
}]; }];
const imperativeTenseOptions: { label: string | JSX.Element, value: T.ImperativeTense }[] = [{ const imperativeTenseOptions: { label: string | JSX.Element, value: T.ImperativeTense }[] = [{
label: <div><i className="fas fa-video mr-2" />imperfective imp.</div>, label: <div><i className="fas fa-video mr-2" />imperfective imperative</div>,
value: "imperfectiveImperative", value: "imperfectiveImperative",
}, { }, {
label: <div><i className="fas fa-camera mr-2" />perfective imp.</div>, label: <div><i className="fas fa-camera mr-2" />perfective imperative</div>,
value: "perfectiveImperative", value: "perfectiveImperative",
}]; }];

View File

@ -1,12 +1,12 @@
import { renderVP, compileVP } from "../../lib/phrase-building/index"; import { renderVP, compileVP } from "../../lib/phrase-building/index";
import * as T from "../../types"; import * as T from "../../types";
import InlinePs from "../InlinePs";
import AbbreviationFormSelector from "./AbbreviationFormSelector"; import AbbreviationFormSelector from "./AbbreviationFormSelector";
import { import {
isPastTense, isPastTense,
completeVPSelection, completeVPSelection,
} from "../../lib/phrase-building/vp-tools"; } from "../../lib/phrase-building/vp-tools";
import { useStickyState } from "../../library"; import { useStickyState } from "../../library";
import Examples from "../Examples";
function VPDisplay({ VP, opts }: { VP: T.VPSelection, opts: T.TextOptions }) { function VPDisplay({ VP, opts }: { VP: T.VPSelection, opts: T.TextOptions }) {
const [form, setForm] = useStickyState<T.FormVersion>({ removeKing: false, shrinkServant: false }, "abbreviationForm"); const [form, setForm] = useStickyState<T.FormVersion>({ removeKing: false, shrinkServant: false }, "abbreviationForm");
@ -21,7 +21,7 @@ function VPDisplay({ VP, opts }: { VP: T.VPSelection, opts: T.TextOptions }) {
</div>; </div>;
} }
const result = compileVP(renderVP(VPComplete), { ...form, OSV }); const result = compileVP(renderVP(VPComplete), { ...form, OSV });
return <div className="text-center mt-2"> return <div className="text-center">
{VP.verb.transitivity === "transitive" && <div className="form-check mb-2"> {VP.verb.transitivity === "transitive" && <div className="form-check mb-2">
<input <input
className="form-check-input" className="form-check-input"
@ -52,7 +52,7 @@ function VPDisplay({ VP, opts }: { VP: T.VPSelection, opts: T.TextOptions }) {
</div> </div>
: <VariationLayer vs={result.ps} opts={opts} /> : <VariationLayer vs={result.ps} opts={opts} />
} }
{result.e && <div className="text-muted"> {result.e && <div className="text-muted mt-3">
{result.e.map((e, i) => <div key={i}>{e}</div>)} {result.e.map((e, i) => <div key={i}>{e}</div>)}
</div>} </div>}
</div> </div>
@ -74,9 +74,7 @@ function whatsAdjustable(VP: T.VPSelectionComplete): "both" | "king" | "servant"
function VariationLayer({ vs, opts }: { vs: T.PsString[], opts: T.TextOptions }) { function VariationLayer({ vs, opts }: { vs: T.PsString[], opts: T.TextOptions }) {
return <div className="mb-2"> return <div className="mb-2">
{vs.map((r, i) => <div key={i}> <Examples opts={opts} lineHeight={0}>{vs}</Examples>
<InlinePs opts={opts}>{r}</InlinePs>
</div>)}
</div>; </div>;
} }

View File

@ -133,17 +133,11 @@ export function VPExplorer(props: {
{ label: "Phrases", value: "phrases" }, { label: "Phrases", value: "phrases" },
{ label: "Quiz", value: "quiz" }, { label: "Quiz", value: "quiz" },
]} ]}
handleChange={(x) => { handleChange={setMode}
// TODO: remove this and implement the imperative in quiz
// if (x === "quiz") {
// }
setMode(x);
}}
/> />
</div> </div>
{(vps.verb && (typeof vps.verb.object === "object") && (vps.verb.isCompound !== "dynamic") && (vps.verb.tenseCategory !== "imperative") &&(mode === "phrases")) && {(vps.verb && (typeof vps.verb.object === "object") && (vps.verb.isCompound !== "dynamic") && (vps.verb.tenseCategory !== "imperative") &&(mode === "phrases")) &&
<div className="text-center mt-4"> <div className="text-center my-2">
<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
</button> </button>
@ -151,10 +145,10 @@ export function VPExplorer(props: {
{mode !== "quiz" && <div className="d-flex flex-row justify-content-around flex-wrap" style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}> {mode !== "quiz" && <div className="d-flex flex-row justify-content-around flex-wrap" style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}>
{mode === "phrases" && <> {mode === "phrases" && <>
<div className="my-2"> <div className="my-2">
{roles.king === "subject"
? <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "king", item: "subject" })}>Subject {roleIcon.king}</div>
: <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "servant", item: "subject" })}>Subject {roleIcon.servant}</div>}
<NPPicker <NPPicker
heading={roles.king === "subject"
? <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "king", item: "subject" })}>Subject {roleIcon.king}</div>
: <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "servant", item: "subject" })}>Subject {roleIcon.servant}</div>}
{..."getNounByTs" in props ? { {..."getNounByTs" in props ? {
getNounByTs: props.getNounByTs, getNounByTs: props.getNounByTs,
getVerbByTs: props.getVerbByTs, getVerbByTs: props.getVerbByTs,
@ -172,12 +166,12 @@ export function VPExplorer(props: {
/> />
</div> </div>
{vps.verb && (vps.verb.object !== "none") && <div className="my-2"> {vps.verb && (vps.verb.object !== "none") && <div className="my-2">
{roles.king === "object"
? <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "king", item: "object" })}>Object {roleIcon.king}</div>
: <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "servant", item: "object" })}>Object {roleIcon.servant}</div>}
{(typeof vps.verb.object === "number") {(typeof vps.verb.object === "number")
? <div className="text-muted">Unspoken 3rd Pers. Masc. Plur.</div> ? <div className="text-muted">Unspoken 3rd Pers. Masc. Plur.</div>
: <NPPicker : <NPPicker
heading={roles.king === "object"
? <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "king", item: "object" })}>Object {roleIcon.king}</div>
: <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "servant", item: "object" })}>Object {roleIcon.servant}</div>}
{..."getNounByTs" in props ? { {..."getNounByTs" in props ? {
getNounByTs: props.getNounByTs, getNounByTs: props.getNounByTs,
getVerbByTs: props.getVerbByTs, getVerbByTs: props.getVerbByTs,