pronoun picker tool
This commit is contained in:
parent
d71064ef43
commit
baf693b6da
|
@ -5,7 +5,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^5.15.4",
|
"@fortawesome/fontawesome-free": "^5.15.4",
|
||||||
"@lingdocs/lingdocs-main": "^0.2.0",
|
"@lingdocs/lingdocs-main": "^0.2.0",
|
||||||
"@lingdocs/pashto-inflector": "^1.3.9",
|
"@lingdocs/pashto-inflector": "^1.4.4",
|
||||||
"@testing-library/jest-dom": "^5.11.4",
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
"@testing-library/react": "^11.1.0",
|
"@testing-library/react": "^11.1.0",
|
||||||
"@testing-library/user-event": "^12.1.10",
|
"@testing-library/user-event": "^12.1.10",
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
import {
|
||||||
|
Types as T,
|
||||||
|
ButtonSelect,
|
||||||
|
} from "@lingdocs/pashto-inflector";
|
||||||
|
import useStickyState from "../../useStickyState";
|
||||||
|
|
||||||
|
const gColors = {
|
||||||
|
masc: "LightSkyBlue",
|
||||||
|
fem: "pink",
|
||||||
|
};
|
||||||
|
|
||||||
|
const labels = {
|
||||||
|
persons: [
|
||||||
|
["1st", "1st pl."],
|
||||||
|
["2nd", "2nd pl."],
|
||||||
|
["3rd", "3rd pl."],
|
||||||
|
],
|
||||||
|
e: [
|
||||||
|
["I", "We"],
|
||||||
|
["You", "You pl."],
|
||||||
|
[{ masc: "He/It", fem: "She/It"}, "They"],
|
||||||
|
],
|
||||||
|
p: {
|
||||||
|
far: [
|
||||||
|
["زه", "مونږ"],
|
||||||
|
["ته", "تاسو"],
|
||||||
|
["هغه", "هغوي"],
|
||||||
|
],
|
||||||
|
near: [
|
||||||
|
["زه", "مونږ"],
|
||||||
|
["ته", "تاسو"],
|
||||||
|
[{ masc: "دی", fem: "دا" }, "دوي"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
type PickerState = { row: number, col: number, gender: T.Gender };
|
||||||
|
|
||||||
|
function personToPickerState(person: T.Person): PickerState {
|
||||||
|
const col = person > 5 ? 1 : 0;
|
||||||
|
const row = Math.floor((person > 5 ? (person - 6) : person) / 2);
|
||||||
|
const gender: T.Gender = (person % 2) ? "fem" : "masc";
|
||||||
|
return { col, row, gender };
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickerStateToPerson(s: PickerState): T.Person {
|
||||||
|
return (s.row * 2)
|
||||||
|
+ (s.gender === "masc" ? 0 : 1)
|
||||||
|
+ (6 * s.col);
|
||||||
|
}
|
||||||
|
|
||||||
|
function PronounPicker({ onChange, pronoun }: { pronoun: Pronoun, onChange: (p: Pronoun) => void }) {
|
||||||
|
const [display, setDisplay] = useStickyState<"persons" | "p" | "e">("persons", "prounoun-picker-display");
|
||||||
|
|
||||||
|
const p = personToPickerState(pronoun.person);
|
||||||
|
function handleClick(row: number, col: number) {
|
||||||
|
onChange({
|
||||||
|
...pronoun,
|
||||||
|
person: pickerStateToPerson({
|
||||||
|
...p,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function handleGenderChange(gender: T.Gender) {
|
||||||
|
onChange({
|
||||||
|
...pronoun,
|
||||||
|
person: pickerStateToPerson({
|
||||||
|
...p,
|
||||||
|
gender,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function handlePronounTypeChange(pronounType: "far" | "near") {
|
||||||
|
onChange({
|
||||||
|
...pronoun,
|
||||||
|
pronounType,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function handleDisplayChange() {
|
||||||
|
const newPerson = display === "persons"
|
||||||
|
? "p"
|
||||||
|
: display === "p"
|
||||||
|
? "e"
|
||||||
|
: "persons";
|
||||||
|
setDisplay(newPerson);
|
||||||
|
}
|
||||||
|
const prs = labels[display];
|
||||||
|
const pSpec = "near" in prs ? prs[pronoun.pronounType] : prs;
|
||||||
|
return <div>
|
||||||
|
<div className="d-flex flex-row justify-content-around mb-3">
|
||||||
|
<ButtonSelect
|
||||||
|
xSmall
|
||||||
|
options={[
|
||||||
|
{ label: "Far", value: "far" },
|
||||||
|
{ label: "Near", value: "near" },
|
||||||
|
]}
|
||||||
|
value={pronoun.pronounType}
|
||||||
|
handleChange={(g) => handlePronounTypeChange(g as "far" | "near")}
|
||||||
|
/>
|
||||||
|
<button className="btn btn-sm btn-outline" onClick={handleDisplayChange}>{display === "persons" ? "#" : display === "p" ? "PS" : "EN"}</button>
|
||||||
|
</div>
|
||||||
|
<table className="table table-bordered" style={{ textAlign: "center", minWidth: "200px", tableLayout: "fixed" }}>
|
||||||
|
<tbody>
|
||||||
|
{pSpec.map((rw, i) => (
|
||||||
|
<tr>
|
||||||
|
{rw.map((r, j) => {
|
||||||
|
const active = (p.row === i && p.col === j)
|
||||||
|
return <td
|
||||||
|
onClick={() => handleClick(i, j)}
|
||||||
|
className={active ? "table-active" : ""}
|
||||||
|
style={active ? { backgroundColor: gColors[p.gender] } : {}}
|
||||||
|
>
|
||||||
|
{typeof r === "string" ? r : r[p.gender]}
|
||||||
|
</td>;
|
||||||
|
})}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div className="text-center">
|
||||||
|
<ButtonSelect
|
||||||
|
options={[
|
||||||
|
{ label: "Masc.", value: "masc", color: gColors.masc },
|
||||||
|
{ label: "Fem.", value: "fem", color: gColors.fem },
|
||||||
|
]}
|
||||||
|
value={p.gender}
|
||||||
|
handleChange={(g) => handleGenderChange(g as T.Gender)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PronounPicker;
|
||||||
|
|
|
@ -3,6 +3,18 @@ title: Equative Explorer 🌎
|
||||||
---
|
---
|
||||||
|
|
||||||
import EquativeExplorer from "../../components/equative-explorer/EquativeExplorer";
|
import EquativeExplorer from "../../components/equative-explorer/EquativeExplorer";
|
||||||
|
import PronounPicker from "../../components/np-picker/PronounPicker";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export function PDem() {
|
||||||
|
const [pronoun, setPronoun] = useState({ type: "pronoun", pronounType: "far", person: 11 });
|
||||||
|
return <div style={{ maxWidth: "200px" }}>
|
||||||
|
<PronounPicker pronoun={pronoun} onChange={setPronoun} />
|
||||||
|
<pre>{JSON.stringify(pronoun, null, " ")}</pre>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<PDem />
|
||||||
|
|
||||||
You can use this tool to explore how to make different equative sentences. Everything that comes out of this will be **gramatically correct**, but the sentences might not always make sense! 🤪
|
You can use this tool to explore how to make different equative sentences. Everything that comes out of this will be **gramatically correct**, but the sentences might not always make sense! 🤪
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,9 @@ import * as typingIssues from "!babel-loader!@lingdocs/mdx-loader!./writing/typi
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import * as games from "!babel-loader!@lingdocs/mdx-loader!./games.mdx";
|
import * as games from "!babel-loader!@lingdocs/mdx-loader!./games.mdx";
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import * as pronounPicker from "!babel-loader!@lingdocs/mdx-loader!./practice-tools/pronoun-picker.mdx";
|
||||||
|
|
||||||
const contentTree = [
|
const contentTree = [
|
||||||
{
|
{
|
||||||
import: intro,
|
import: intro,
|
||||||
|
@ -245,6 +248,16 @@ const contentTree = [
|
||||||
import: games,
|
import: games,
|
||||||
slug: "games",
|
slug: "games",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
heading: "Practice Tools 🔧",
|
||||||
|
subdirectory: "practice-tools",
|
||||||
|
chapters: [
|
||||||
|
{
|
||||||
|
import: pronounPicker,
|
||||||
|
slug: "pronoun-picker",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const content = contentTree.map((item) => {
|
export const content = contentTree.map((item) => {
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
---
|
||||||
|
title: Pronoun Picker
|
||||||
|
---
|
||||||
|
|
||||||
|
import PronounPicker from "../../components/np-picker/PronounPicker";
|
||||||
|
import {
|
||||||
|
defaultTextOptions as opts,
|
||||||
|
InlinePs,
|
||||||
|
} from "@lingdocs/pashto-inflector";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export function randomP(p) {
|
||||||
|
let newP = 0;
|
||||||
|
do {
|
||||||
|
newP = Math.floor(Math.random() * 12);
|
||||||
|
} while (newP === p);
|
||||||
|
return newP;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RPicker() {
|
||||||
|
const [pronoun, setPronoun] = useState({ type: "pronoun", pronounType: "far", person: randomP() });
|
||||||
|
function handleRandom() {
|
||||||
|
const person = randomP(pronoun.person);
|
||||||
|
setPronoun({
|
||||||
|
...pronoun,
|
||||||
|
person,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return <div className="text-center">
|
||||||
|
<div className="my-4" style={{ maxWidth: "375px", margin: "0 auto" }}>
|
||||||
|
<PronounPicker pronoun={pronoun} onChange={setPronoun} />
|
||||||
|
</div>
|
||||||
|
<button className="btn btn-lg btn-primary mt-2">
|
||||||
|
<i class="fas fa-random" onClick={handleRandom} />
|
||||||
|
</button>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
Use this pronoun picker to help you drill different sentences. Choose different pronouns to drill a friend, or press the <i class="fas fa-random"></i> button to get a random selection.
|
||||||
|
|
||||||
|
<div className="mt-4">
|
||||||
|
<RPicker />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<details className="mt-4">
|
||||||
|
<summary>Show Second Picker</summary>
|
||||||
|
<RPicker />
|
||||||
|
</details>
|
|
@ -45,6 +45,7 @@ type Compliment = {
|
||||||
type Participle = {
|
type Participle = {
|
||||||
type: "participle",
|
type: "participle",
|
||||||
entry: VerbEntry,
|
entry: VerbEntry,
|
||||||
|
np?: NounPhrase,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Pronoun = {
|
type Pronoun = {
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
export default function useStickyState<T>(defaultValue: T, key: string): {
|
export default function useStickyState<T>(defaultValue: T, key: string): [
|
||||||
value: T,
|
value: T,
|
||||||
setValue: React.Dispatch<React.SetStateAction<T>>,
|
setValue: React.Dispatch<React.SetStateAction<T>>,
|
||||||
} {
|
] {
|
||||||
|
|
||||||
const [value, setValue] = useState<T>(() => {
|
const [value, setValue] = useState<T>(() => {
|
||||||
const stickyValue = window.localStorage.getItem(key);
|
const stickyValue = window.localStorage.getItem(key);
|
||||||
if (stickyValue === null) return defaultValue;
|
if (stickyValue === null) return defaultValue;
|
||||||
|
@ -20,5 +19,5 @@ export default function useStickyState<T>(defaultValue: T, key: string): {
|
||||||
window.localStorage.setItem(key, JSON.stringify(value));
|
window.localStorage.setItem(key, JSON.stringify(value));
|
||||||
}, [key, value]);
|
}, [key, value]);
|
||||||
|
|
||||||
return {value, setValue};
|
return [value, setValue];
|
||||||
}
|
}
|
|
@ -19,7 +19,7 @@ const UserContext = createContext<
|
||||||
|
|
||||||
// TODO: persisting user in local state
|
// TODO: persisting user in local state
|
||||||
function UserProvider({ children }: any) {
|
function UserProvider({ children }: any) {
|
||||||
const {value, setValue} = useStickyState<AT.LingdocsUser | undefined>(
|
const [value, setValue] = useStickyState<AT.LingdocsUser | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
"saved-user",
|
"saved-user",
|
||||||
);
|
);
|
||||||
|
|
|
@ -1684,10 +1684,10 @@
|
||||||
pbf "^3.2.1"
|
pbf "^3.2.1"
|
||||||
rambda "^6.7.0"
|
rambda "^6.7.0"
|
||||||
|
|
||||||
"@lingdocs/pashto-inflector@^1.3.5":
|
"@lingdocs/pashto-inflector@^1.4.4":
|
||||||
version "1.3.5"
|
version "1.4.4"
|
||||||
resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-1.3.5.tgz#cfc311462c686e5591f12ee68b333a2ec479f428"
|
resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-1.4.4.tgz#5015bf1e4abd913bdb2cbcc08a89ab64a7194d9e"
|
||||||
integrity sha512-Asxu773Z9+0Gxi8wkSD6x3JYcSeJmXqgoHQu1Hvph1oOAac3t8Bn0uXC/OGO5p1leilEHePJT+hkMFmURTArcw==
|
integrity sha512-RGf3AZFpy4JWzjWLeeGNLvy1PsDljRcDF4mQIqMPrFeakkuT4h3/exbGAANehNWGt9hm6LbPvXyXQmxe7SWaXg==
|
||||||
dependencies:
|
dependencies:
|
||||||
classnames "^2.2.6"
|
classnames "^2.2.6"
|
||||||
pbf "^3.2.1"
|
pbf "^3.2.1"
|
||||||
|
|
Loading…
Reference in New Issue