better UI for removing king

This commit is contained in:
lingdocs 2022-08-02 13:27:19 -05:00
parent dc75525e74
commit a3a0cd9319
8 changed files with 149 additions and 20 deletions

View File

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

@ -1,15 +1,19 @@
import * as T from "../../types"; import * as T from "../../types";
import { useState } from "react"; import { useState } from "react";
import AdjectivePicker from "./AdjectivePicker"; import AdjectivePicker from "./AdjectivePicker";
import classNames from "classnames";
function AdjectiveManager(props: { function AdjectiveManager(props: {
adjectives: T.AdjectiveSelection[], adjectives: T.AdjectiveSelection[],
entryFeeder: T.EntryFeeder, entryFeeder: T.EntryFeeder,
opts: T.TextOptions, opts: T.TextOptions,
demonstrative: T.NounSelection["demonstrative"],
onChange: (adjs: T.AdjectiveSelection[]) => void, onChange: (adjs: T.AdjectiveSelection[]) => void,
onDemonstrativeChange: (dem: T.NounSelection["demonstrative"]) => void,
phraseIsComplete: boolean, phraseIsComplete: boolean,
}) { }) {
const [adding, setAdding] = useState<boolean>(false); const [adding, setAdding] = useState<boolean>(false);
const [addingDemonstrative, setAddingDemonstrative] = useState<boolean>(false);
function handleChange(i: number) { function handleChange(i: number) {
return (a: T.AdjectiveSelection | undefined) => { return (a: T.AdjectiveSelection | undefined) => {
if (a === undefined) return; if (a === undefined) return;
@ -53,6 +57,21 @@ function AdjectiveManager(props: {
onChange={handleAddNew} onChange={handleAddNew}
/> />
</div>} </div>}
{addingDemonstrative && <div>
<div className="d-flex flex-row justify-content-between mb-1">
<div>Add Demonstrative</div>
<div className="clickable" onClick={() => {
setAddingDemonstrative(false);
props.onDemonstrativeChange(undefined);
}}>
<i className="fas fa-trash" />
</div>
</div>
<DemonstrativePicker
demonstrative={props.demonstrative}
onChange={props.onDemonstrativeChange}
/>
</div>}
{props.adjectives.map((adj, i) => <div key={i}> {props.adjectives.map((adj, i) => <div key={i}>
<div className="d-flex flex-row justify-content-between"> <div className="d-flex flex-row justify-content-between">
<div>Adjective</div> <div>Adjective</div>
@ -75,12 +94,55 @@ function AdjectiveManager(props: {
onChange={handleChange(i)} onChange={handleChange(i)}
/> />
</div>)} </div>)}
{!adding && !props.adjectives.length && <h6 className="clickable" style={{ float: "right" }}> {/* {!adding && !props.adjectives.length && <h6 className="clickable" style={{ float: "right" }}>
<div className="clickable" onClick={() => setAdding(true)}>+ Adj.</div> <div className="clickable" onClick={() => setAdding(true)}>+ Adj.</div>
</h6>} */}
{!addingDemonstrative && !props.demonstrative && <h6 className="clickable mr-2" style={{ float: "right" }}>
<div className="clickable" onClick={() => setAddingDemonstrative(true)}>+ Demons.</div>
</h6>} </h6>}
</div>; </div>;
} }
function DemonstrativePicker({ demonstrative, onChange }: {
demonstrative: T.NounSelection["demonstrative"],
onChange: (dem: T.NounSelection["demonstrative"]) => void,
}) {
function handleDChange(d: "daa" | "hagha" | "dagha") {
if (!demonstrative) {
onChange({
type: "demonstrative",
demonstrative: d,
hideNoun: false,
});
} else {
onChange({
...demonstrative,
demonstrative: d,
});
}
}
return <div className="d-flex flex-row justify-content-around py-1">
<div>
<button
className={classNames("btn", "btn-outline-secondary", { active: demonstrative?.demonstrative === "daa" })}
onClick={() => handleDChange("daa")}
>دا</button>
</div>
<div>
<button
className={classNames("btn", "btn-outline-secondary", { active: demonstrative?.demonstrative === "hagha" })}
onClick={() => handleDChange("hagha")}
>هغه</button>
</div>
<div>
<button
className={classNames("btn", "btn-outline-secondary", { active: demonstrative?.demonstrative === "dagha" })}
onClick={() => handleDChange("dagha")}
>دغه</button>
</div>
</div>;
}
function remove<X>(arr: X[], i: number): X[] { function remove<X>(arr: X[], i: number): X[] {
return [ return [
...arr.slice(0, i), ...arr.slice(0, i),

View File

@ -85,6 +85,14 @@ function NPNounPicker(props: {
}); });
} }
} }
function handleDemonstrativeUpdate(demonstrative: undefined | T.NounSelection["demonstrative"]) {
if (props.noun) {
props.onChange({
...props.noun,
demonstrative,
});
}
}
return <div style={{ maxWidth: "225px", minWidth: "125px" }}> return <div style={{ maxWidth: "225px", minWidth: "125px" }}>
{/* {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">
@ -102,9 +110,11 @@ function NPNounPicker(props: {
{props.noun && <AdjectiveManager {props.noun && <AdjectiveManager
phraseIsComplete={props.phraseIsComplete} phraseIsComplete={props.phraseIsComplete}
adjectives={props.noun?.adjectives} adjectives={props.noun?.adjectives}
demonstrative={props.noun.demonstrative}
entryFeeder={props.entryFeeder} entryFeeder={props.entryFeeder}
opts={props.opts} opts={props.opts}
onChange={handelAdjectivesUpdate} onChange={handelAdjectivesUpdate}
onDemonstrativeChange={handleDemonstrativeUpdate}
/>} />}
<h6>Noun</h6> <h6>Noun</h6>
{!(props.noun && props.noun.dynamicComplement) ? <div> {!(props.noun && props.noun.dynamicComplement) ? <div>

View File

@ -108,7 +108,7 @@ function NPPicker(props: {
: <div></div>; : <div></div>;
const possesiveLabel = props.np?.selection.type === "participle" ? "Subj/Obj" : "Possesor"; const possesiveLabel = props.np?.selection.type === "participle" ? "Subj/Obj" : "Possesor";
return <div style={{ return <div style={{
opacity: props.isRemoved ? 0.6 : 1, opacity: props.isRemoved ? 0.5 : 1,
}}> }}>
<div className="d-flex flex-row justify-content-between"> <div className="d-flex flex-row justify-content-between">
<div></div> <div></div>

View File

@ -114,5 +114,6 @@ export function makeNounSelection(entry: T.NounEntry, old: T.NounSelection | und
adjectives: (!dynamicComplement && old) ? old.adjectives : [], adjectives: (!dynamicComplement && old) ? old.adjectives : [],
possesor: !dynamicComplement ? old?.possesor : undefined, possesor: !dynamicComplement ? old?.possesor : undefined,
dynamicComplement, dynamicComplement,
demonstrative: undefined,
}; };
} }

View File

@ -103,11 +103,12 @@ function VPPicker({ opts, vps, onChange, entryFeeder }: {
heading={roles.king === "subject" heading={roles.king === "subject"
? <div className="h5 text-center"> ? <div className="h5 text-center">
Subj. <span onClick={() => setShowingExplanation({ role: "king", item: "subject" })}>{roleIcon.king}</span> Subj. <span onClick={() => setShowingExplanation({ role: "king", item: "subject" })}>{roleIcon.king}</span>
{/* {(rendered && rendered.whatsAdjustable !== "servant") && {(rendered && rendered.whatsAdjustable !== "servant") &&
<span onClick={() => adjustVps({ type: "toggle king remove" })} className="mx-2 clickable"> <KingRemover
{!VPS?.form.removeKing ? "🫣" : "🚫" } onChange={() => adjustVps({ type: "toggle king remove" })}
</span> showKing={!VPS?.form.removeKing}
} */} />
}
</div> </div>
: <div className="h5 text-center"> : <div className="h5 text-center">
Subj. Subj.
@ -115,9 +116,10 @@ function VPPicker({ opts, vps, onChange, entryFeeder }: {
<span className="clickable" onClick={() => setShowingExplanation({ role: "servant", item: "subject" })}>{roleIcon.servant}</span> <span className="clickable" onClick={() => setShowingExplanation({ role: "servant", item: "subject" })}>{roleIcon.servant}</span>
{` `} {` `}
{(rendered && rendered.whatsAdjustable !== "king") && {(rendered && rendered.whatsAdjustable !== "king") &&
<span onClick={() => adjustVps({ type: "toggle servant shrink" })} className="mx-2 clickable"> <ServantShrinker
{!servantIsShrunk ? "🪄" : "👶"} shrunk={servantIsShrunk}
</span> onClick={() => adjustVps({ type: "toggle servant shrink" })}
/>
} }
</div>} </div>}
entryFeeder={entryFeeder} entryFeeder={entryFeeder}
@ -146,11 +148,12 @@ function VPPicker({ opts, vps, onChange, entryFeeder }: {
heading={roles.king === "object" heading={roles.king === "object"
? <div className="h5 text-center"> ? <div className="h5 text-center">
Obj. <span onClick={() => setShowingExplanation({ role: "king", item: "object" })}>{roleIcon.king}</span> Obj. <span onClick={() => setShowingExplanation({ role: "king", item: "object" })}>{roleIcon.king}</span>
{/* {(rendered && rendered.whatsAdjustable !== "servant") && {(rendered && rendered.whatsAdjustable !== "servant") &&
<span onClick={() => adjustVps({ type: "toggle king remove" })} className="mx-2 clickable"> <KingRemover
{!VPS?.form.removeKing ? "🙈" : "🚫"} onChange={() => adjustVps({ type: "toggle king remove" })}
</span> showKing={!VPS?.form.removeKing}
} */} />
}
</div> </div>
: <div className="h5 text-center"> : <div className="h5 text-center">
Obj. Obj.
@ -158,9 +161,7 @@ function VPPicker({ opts, vps, onChange, entryFeeder }: {
<span className="clickable" onClick={() => setShowingExplanation({ role: "servant", item: "object" })}>{roleIcon.servant}</span> <span className="clickable" onClick={() => setShowingExplanation({ role: "servant", item: "object" })}>{roleIcon.servant}</span>
{` `} {` `}
{(rendered && rendered.whatsAdjustable !== "king") && {(rendered && rendered.whatsAdjustable !== "king") &&
<span onClick={() => adjustVps({ type: "toggle servant shrink" })} className="mx-2 clickable"> <ServantShrinker shrunk={servantIsShrunk} onClick={() => adjustVps({ type: "toggle servant shrink" })} />
{!servantIsShrunk ? "🪄" : "👶"}
</span>
} }
</div>} </div>}
entryFeeder={entryFeeder} entryFeeder={entryFeeder}
@ -213,4 +214,28 @@ function VPPicker({ opts, vps, onChange, entryFeeder }: {
</div>; </div>;
} }
function ServantShrinker({ shrunk, onClick }: {
shrunk: boolean;
onClick: () => void;
}) {
return <span className="mx-2 clickable" onClick={onClick}>
{!shrunk ? "🪄" : "👶"}
</span>;
}
function KingRemover({ showKing, onChange }: {
showKing: boolean;
onChange: () => void;
}) {
return <span className="form-check form-check-inline ml-3">
<input
checked={showKing}
onChange={onChange}
className="form-check-input"
type="checkbox"
id="showKingCheck"
/>
</span>;
}
export default VPPicker; export default VPPicker;

View File

@ -71,9 +71,24 @@ export function renderNounSelection(n: T.NounSelection, inflected: boolean, role
ps: pashto, ps: pashto,
e: english, e: english,
possesor: renderPossesor(n.possesor, role), possesor: renderPossesor(n.possesor, role),
demonstrative: renderDemonstrative(n.demonstrative, inflected && n.number === "plural"),
}; };
} }
function renderDemonstrative(demonstrative: T.DemonstrativeSelection | undefined, plurInflected: boolean): T.Rendered<T.DemonstrativeSelection> | undefined {
if (!demonstrative) {
return undefined;
}
return {
...demonstrative,
ps: demonstrative.demonstrative === "daa"
? (plurInflected ? { p: "دې", f: "de" } : { p: "دا", f: "daa" })
: demonstrative.demonstrative === "dagha"
? (plurInflected ? { p: "دغه", f: "dágha" } : { p: "دغو", f: "dágho" })
: (plurInflected ? { p: "هغه", f: "hágha" } : { p: "هغو", f: "hágho" })
}
}
function renderPronounSelection(p: T.PronounSelection, inflected: boolean, englishInflected: boolean, role: "servant" | "king" | "none"): T.Rendered<T.PronounSelection> { function renderPronounSelection(p: T.PronounSelection, inflected: boolean, englishInflected: boolean, role: "servant" | "king" | "none"): T.Rendered<T.PronounSelection> {
const [row, col] = getVerbBlockPosFromPerson(p.person); const [row, col] = getVerbBlockPosFromPerson(p.person);
return { return {

View File

@ -649,6 +649,13 @@ export type NounSelection = {
dynamicComplement?: boolean, dynamicComplement?: boolean,
adjectives: AdjectiveSelection[], adjectives: AdjectiveSelection[],
possesor: undefined | PossesorSelection, possesor: undefined | PossesorSelection,
demonstrative: undefined | DemonstrativeSelection,
};
export type DemonstrativeSelection = {
type: "demonstrative",
demonstrative: "daa" | "hagha" | "dagha",
hideNoun: boolean,
}; };
export type AdverbSelection = { export type AdverbSelection = {
@ -708,6 +715,7 @@ export type Rendered<
| AdjectiveSelection | AdjectiveSelection
| SandwichSelection<Sandwich> | SandwichSelection<Sandwich>
| ComplementSelection | ComplementSelection
| DemonstrativeSelection
| ComplementSelection["selection"] | ComplementSelection["selection"]
| UnselectedComplementSelection | UnselectedComplementSelection
| undefined | undefined
@ -757,6 +765,13 @@ export type Rendered<
inflected: boolean, inflected: boolean,
person: Person, person: Person,
} }
: T extends DemonstrativeSelection
? {
type: "demonstrative",
demonstrative: DemonstrativeSelection["demonstrative"],
hideNoun: boolean,
ps: PsString,
}
: T extends ComplementSelection : T extends ComplementSelection
? { ? {
type: "complement", type: "complement",
@ -797,6 +812,7 @@ export type Rendered<
shrunken: boolean, shrunken: boolean,
np: Rendered<NPSelection>, np: Rendered<NPSelection>,
}, },
demonstrative?: Rendered<DemonstrativeSelection>,
}; };
export type EPSelectionState = { export type EPSelectionState = {