try with context

This commit is contained in:
lingdocs 2021-09-18 00:43:00 -04:00
parent 16066df914
commit 4b820ba231
24 changed files with 355 additions and 79 deletions

View File

@ -4,7 +4,8 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^5.15.2", "@fortawesome/fontawesome-free": "^5.15.2",
"@lingdocs/pashto-inflector": "^0.9.3", "@lingdocs/lingdocs-main": "^0.0.4",
"@lingdocs/pashto-inflector": "^1.0.5",
"@testing-library/jest-dom": "^4.2.4", "@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2", "@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2", "@testing-library/user-event": "^7.1.2",
@ -12,6 +13,7 @@
"@types/node": "^14.14.35", "@types/node": "^14.14.35",
"@types/react": "^17.0.3", "@types/react": "^17.0.3",
"@types/react-dom": "^17.0.2", "@types/react-dom": "^17.0.2",
"@types/react-router-dom": "^5.1.9",
"bootstrap": "4.5.3", "bootstrap": "4.5.3",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"markdown-to-jsx": "^7.1.3", "markdown-to-jsx": "^7.1.3",

View File

@ -8,7 +8,7 @@
import React, { useState } from "react"; import React, { useState } from "react";
// eslint-disable-next-line // eslint-disable-next-line
import { BrowserRouter as Router, Route, withRouter, Switch } from "react-router-dom"; import { BrowserRouter as Router, Route, withRouter, Switch, RouteComponentProps } from "react-router-dom";
import "./App.css"; import "./App.css";
import Page404 from "./pages/404"; import Page404 from "./pages/404";
import Chapter from "./components/Chapter"; import Chapter from "./components/Chapter";
@ -17,6 +17,8 @@ import Sidebar from "./components/Sidebar";
import Header from "./components/Header"; import Header from "./components/Header";
import TableOfContentsPage from "./pages/TableOfContentsPage"; import TableOfContentsPage from "./pages/TableOfContentsPage";
import { useEffect } from "react"; import { useEffect } from "react";
import { useUser } from "./user-context";
import { AT } from "@lingdocs/lingdocs-main";
import ReactGA from "react-ga"; import ReactGA from "react-ga";
const chapters = content.reduce((chapters, item) => ( const chapters = content.reduce((chapters, item) => (
item.content item.content
@ -31,10 +33,21 @@ if (prod) {
ReactGA.set({ anonymizeIp: true }); ReactGA.set({ anonymizeIp: true });
} }
function App(props) { function App(props: RouteComponentProps) {
const [navOpen, setNavOpen] = useState(false); const [navOpen, setNavOpen] = useState(false);
const { setUser } = useUser();
useEffect(() => { useEffect(() => {
ReactGA.pageview(window.location.pathname); ReactGA.pageview(window.location.pathname);
fetch("https://account.lingdocs.com/api/user").then((res) => res.json()).then((res) => {
console.log("fetched user info");
if (res.user) {
const user = res.user as AT.LingdocsUser
setUser(user);
} else {
setUser(undefined);
}
}).catch(console.error);
// eslint-disable-next-line
}, []); }, []);
useEffect(() => { useEffect(() => {
window.scroll(0, 0); window.scroll(0, 0);
@ -57,7 +70,7 @@ function App(props) {
<Route path="/" exact> <Route path="/" exact>
<TableOfContentsPage /> <TableOfContentsPage />
</Route> </Route>
{chapters.map((chapter) => ( {chapters.map((chapter: any) => (
<Route key={chapter.path} path={chapter.path}> <Route key={chapter.path} path={chapter.path}>
<Chapter>{chapter}</Chapter> <Chapter>{chapter}</Chapter>
</Route> </Route>

6
src/UserContext.tsx Normal file
View File

@ -0,0 +1,6 @@
import React from "react";
import { AT } from "@lingdocs/lingdocs-main";
const UserContext = React.createContext<undefined | AT.LingdocsUser>(undefined);
export default UserContext;

View File

@ -2,29 +2,31 @@ import React from "react";
import Carousel from "./Carousel"; import Carousel from "./Carousel";
import { import {
InlinePs, InlinePs,
removeFVariants, removeFVarients,
InflectionsTable, InflectionsTable,
inflectWord, inflectWord,
defaultTextOptions as opts, defaultTextOptions as opts,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
function InflectionCarousel({ items }) { function InflectionCarousel({ items }: any) {
return ( return (
<div className="mt-3"> <div className="mt-3">
<Carousel items={items} render={(item) => { <Carousel items={items} render={(item: any) => {
const inf = inflectWord(item.entry); const infOut = inflectWord(item.entry);
if (!inf) { if (!infOut || !infOut.inflections) {
return ( return (
<div>Oops! No inflections for <InlinePs opts={opts} ps={item.entry} /></div> // @ts-ignore
<div>Oops! No inflections for <InlinePs opts={opts} />{item.entry}</div>
); );
} }
return { return {
// @ts-ignore
title: <InlinePs opts={opts} ps={{ title: <InlinePs opts={opts} ps={{
...removeFVariants(item.entry), ...removeFVarients(item.entry),
e: item.def, e: item.def,
}} />, }} />,
body: <InflectionsTable body: <InflectionsTable
inf={inf} inf={infOut.inflections}
textOptions={opts} textOptions={opts}
/>, />,
}; };

View File

@ -7,39 +7,66 @@
*/ */
/* eslint-disable import/no-webpack-loader-syntax */ /* eslint-disable import/no-webpack-loader-syntax */
// @ts-ignore
import * as intro from "!babel-loader!mdx-loader!./intro.mdx"; import * as intro from "!babel-loader!mdx-loader!./intro.mdx";
// @ts-ignore
import * as presentEquative from "!babel-loader!mdx-loader!./equatives/present-equative.mdx" import * as presentEquative from "!babel-loader!mdx-loader!./equatives/present-equative.mdx"
// @ts-ignore
import * as subjunctiveHabitualEquative from "!babel-loader!mdx-loader!./equatives/subjunctive-habitual-equative.mdx"; import * as subjunctiveHabitualEquative from "!babel-loader!mdx-loader!./equatives/subjunctive-habitual-equative.mdx";
// @ts-ignore
import * as otherEquatives from "!babel-loader!mdx-loader!./equatives/other-equatives.mdx"; import * as otherEquatives from "!babel-loader!mdx-loader!./equatives/other-equatives.mdx";
// @ts-ignore
import * as nounsGender from "!babel-loader!mdx-loader!./nouns/nouns-gender.mdx"; import * as nounsGender from "!babel-loader!mdx-loader!./nouns/nouns-gender.mdx";
// @ts-ignore
import * as nounsUnisex from "!babel-loader!mdx-loader!./nouns/nouns-unisex.mdx"; import * as nounsUnisex from "!babel-loader!mdx-loader!./nouns/nouns-unisex.mdx";
// @ts-ignore
import * as nounsPlural from "!babel-loader!mdx-loader!./nouns/nouns-plural.mdx"; import * as nounsPlural from "!babel-loader!mdx-loader!./nouns/nouns-plural.mdx";
// @ts-ignore
import * as arabicPlurals from "!babel-loader!mdx-loader!./nouns/arabic-plurals.mdx"; import * as arabicPlurals from "!babel-loader!mdx-loader!./nouns/arabic-plurals.mdx";
// @ts-ignore
import * as bundledPlurals from "!babel-loader!mdx-loader!./nouns/bundled-plurals.mdx"; import * as bundledPlurals from "!babel-loader!mdx-loader!./nouns/bundled-plurals.mdx";
// @ts-ignore
import * as verbAspect from "!babel-loader!mdx-loader!./verbs/verb-aspect.mdx"; import * as verbAspect from "!babel-loader!mdx-loader!./verbs/verb-aspect.mdx";
// @ts-ignore
import * as verbsIntro from "!babel-loader!mdx-loader!./verbs/verbs-intro.mdx"; import * as verbsIntro from "!babel-loader!mdx-loader!./verbs/verbs-intro.mdx";
// @ts-ignore
import * as presentVerbs from "!babel-loader!mdx-loader!./verbs/present-verbs.mdx"; import * as presentVerbs from "!babel-loader!mdx-loader!./verbs/present-verbs.mdx";
// @ts-ignore
import * as subjunctiveVerbs from "!babel-loader!mdx-loader!./verbs/subjunctive-verbs.mdx"; import * as subjunctiveVerbs from "!babel-loader!mdx-loader!./verbs/subjunctive-verbs.mdx";
// @ts-ignore
import * as futureVerbs from "!babel-loader!mdx-loader!./verbs/future-verbs.mdx"; import * as futureVerbs from "!babel-loader!mdx-loader!./verbs/future-verbs.mdx";
// @ts-ignore
import * as imperativeVerbs from "!babel-loader!mdx-loader!./verbs/imperative-verbs.mdx"; import * as imperativeVerbs from "!babel-loader!mdx-loader!./verbs/imperative-verbs.mdx";
// @ts-ignore
import * as verbEndings from "!babel-loader!mdx-loader!./verbs/verb-endings.mdx"; import * as verbEndings from "!babel-loader!mdx-loader!./verbs/verb-endings.mdx";
// @ts-ignore
import * as rootsAndStems from "!babel-loader!mdx-loader!./verbs/roots-and-stems.mdx"; import * as rootsAndStems from "!babel-loader!mdx-loader!./verbs/roots-and-stems.mdx";
// @ts-ignore
import * as sentenceStructure from "!babel-loader!mdx-loader!./verbs/sentence-structure.mdx"; import * as sentenceStructure from "!babel-loader!mdx-loader!./verbs/sentence-structure.mdx";
// @ts-ignore
import * as pronounsBasic from "!babel-loader!mdx-loader!./pronouns/pronouns-basic.mdx"; import * as pronounsBasic from "!babel-loader!mdx-loader!./pronouns/pronouns-basic.mdx";
// @ts-ignore
import * as pronounsMini from "!babel-loader!mdx-loader!./pronouns/pronouns-mini.mdx"; import * as pronounsMini from "!babel-loader!mdx-loader!./pronouns/pronouns-mini.mdx";
// @ts-ignore
import * as directionalPronouns from "!babel-loader!mdx-loader!./pronouns/pronouns-directional.mdx"; import * as directionalPronouns from "!babel-loader!mdx-loader!./pronouns/pronouns-directional.mdx";
// @ts-ignore
import * as inflectionIntro from "!babel-loader!mdx-loader!./inflection/inflection-intro.mdx"; import * as inflectionIntro from "!babel-loader!mdx-loader!./inflection/inflection-intro.mdx";
// @ts-ignore
import * as inflectionPatterns from "!babel-loader!mdx-loader!./inflection/inflection-patterns.mdx"; import * as inflectionPatterns from "!babel-loader!mdx-loader!./inflection/inflection-patterns.mdx";
// @ts-ignore
import * as feminineInflection from "!babel-loader!mdx-loader!./inflection/feminine-inflection.mdx"; import * as feminineInflection from "!babel-loader!mdx-loader!./inflection/feminine-inflection.mdx";
// @ts-ignore
import * as sandwiches from "!babel-loader!mdx-loader!./sandwiches/sandwiches.mdx"; import * as sandwiches from "!babel-loader!mdx-loader!./sandwiches/sandwiches.mdx";
// @ts-ignore
import * as theFiveYeys from "!babel-loader!mdx-loader!./writing/the-five-yeys.mdx"; import * as theFiveYeys from "!babel-loader!mdx-loader!./writing/the-five-yeys.mdx";
// @ts-ignore
import * as typingIssues from "!babel-loader!mdx-loader!./writing/typing-issues.mdx"; import * as typingIssues from "!babel-loader!mdx-loader!./writing/typing-issues.mdx";
const contentTree = [ const contentTree = [
@ -196,7 +223,7 @@ const contentTree = [
]; ];
export const content = contentTree.map((item) => { export const content = contentTree.map((item) => {
function prepareChapter(chp, subdir) { function prepareChapter(chp: any, subdir?: any) {
return { return {
path: subdir ? `/${subdir}/${chp.slug}/` : `/${chp.slug}/`, path: subdir ? `/${subdir}/${chp.slug}/` : `/${chp.slug}/`,
slug: chp.slug, slug: chp.slug,
@ -209,30 +236,34 @@ export const content = contentTree.map((item) => {
? prepareChapter(item) ? prepareChapter(item)
: { : {
...item, ...item,
chapters: item.chapters.map((c) => { chapters: item.chapters?.map((c) => {
return prepareChapter(c, item.subdirectory); return prepareChapter(c, item.subdirectory);
}), }),
}; };
}).map((item, i, items) => { }).map((item, i, items) => {
// make the next and previous page information for each chapter // make the next and previous page information for each chapter
function withNextPrev(current, index, arr) { function withNextPrev(current: any, index: any, arr: any) {
function getInfo(x) { function getInfo(x: any) {
return x.content return x.content
? { frontMatter: x.frontMatter, path: x.path } ? { frontMatter: x.frontMatter, path: x.path }
: { frontMatter: x.chapters[0].frontMatter, path: x.chapters[0].path }; // TODO: KILL THIS? : { frontMatter: x.chapters[0].frontMatter, path: x.chapters[0].path }; // TODO: KILL THIS?
} }
function getNextOutsideItem() { function getNextOutsideItem() {
// @ts-ignore
return items[i+1].content return items[i+1].content
// if it's a single chapter section, get that chapter // if it's a single chapter section, get that chapter
? items[i+1] ? items[i+1]
// if it's a section with multiple chapters, get the first chapter // if it's a section with multiple chapters, get the first chapter
// @ts-ignore
: items[i+1].chapters[0]; : items[i+1].chapters[0];
} }
function getPrevOutsideItem() { function getPrevOutsideItem() {
// @ts-ignore
return items[i-1].content return items[i-1].content
// if it's a single chapter section, get that chapter // if it's a single chapter section, get that chapter
? items[i-1] ? items[i-1]
// if it's a section with multiple chapters, get the last chapter // if it's a section with multiple chapters, get the last chapter
// @ts-ignore
: items[i-1].chapters[items[i-1].chapters.length - 1]; : items[i-1].chapters[items[i-1].chapters.length - 1];
} }
const next = index < arr.length - 1 const next = index < arr.length - 1
@ -259,11 +290,13 @@ export const content = contentTree.map((item) => {
} : {}, } : {},
}; };
} }
// @ts-ignore
if (item.content) { if (item.content) {
return withNextPrev(item, i, items); return withNextPrev(item, i, items);
} }
return { return {
...item, ...item,
// @ts-ignore
chapters: item.chapters.map((chapter, j, chapters) => ( chapters: item.chapters.map((chapter, j, chapters) => (
withNextPrev(chapter, j, chapters) withNextPrev(chapter, j, chapters)
)), )),

View File

@ -19,7 +19,7 @@ import {
Examples, Examples,
InlinePs, InlinePs,
grammarUnits, grammarUnits,
removeFVariants, removeFVarients,
InflectionsTable, InflectionsTable,
inflectWord, inflectWord,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";

View File

@ -17,10 +17,6 @@ import {
defaultTextOptions as opts, defaultTextOptions as opts,
Examples, Examples,
InlinePs, InlinePs,
grammarUnits,
removeFVariants,
InflectionsTable,
inflectWord,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
import Carousel from "../../components/Carousel"; import Carousel from "../../components/Carousel";
import Table from "../../components/Table"; import Table from "../../components/Table";

View File

@ -33,4 +33,4 @@ This is very much a work in progress. 🏗👷‍♂️ I am slowly adding more
> "Part of the task of the grammarian is ... to unravel the complexities of languages, and, as far as possible, simplify them." Frank Palmer - [Grammar](https://www.amazon.com/gp/product/B000S5VSAS) > "Part of the task of the grammarian is ... to unravel the complexities of languages, and, as far as possible, simplify them." Frank Palmer - [Grammar](https://www.amazon.com/gp/product/B000S5VSAS)
I hope this grammar helps to show that **Pashto isn't difficult... it's rich and beautiful**. I hope this grammar helps to show that **Pashto isn't difficult... it's rich and beautiful**.

View File

@ -8,13 +8,15 @@ import {
Examples, Examples,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
import genderColors from "../../lib/gender-colors"; import genderColors from "../../lib/gender-colors";
import GenderGame from "../../games/GenderGame";
import { firstVariation } from "../../lib/text-tools"; import { firstVariation } from "../../lib/text-tools";
import GenderTable from "../../components/GenderTable"; import GenderTable from "../../components/GenderTable";
import Link from "../../components/Link"; import Link from "../../components/Link";
import words from "../../words/nouns-adjs"; import words from "../../words/nouns-adjs";
export const femColor = genderColors.f; export const femColor = genderColors.f;
export const mascColor = genderColors.m; export const mascColor = genderColors.m;
import nounGenderGame1 from "../../games/games";
import nounGenderGame2 from "../../games/games";
import GameDisplay from "../../games/GameDisplay";
export const femEndingWConsonant = words.filter((w) => w.category === "consonant-fem"); export const femEndingWConsonant = words.filter((w) => w.category === "consonant-fem");
@ -109,7 +111,7 @@ All nouns in Pashto are either <Masc /> or <Fem />. Thankfully, you can pretty m
- Words ending in <InlinePs opts={opts} ps={{p:"و", f:"oo"}} /> can be either <Masc /> or <Fem />. - Words ending in <InlinePs opts={opts} ps={{p:"و", f:"oo"}} /> can be either <Masc /> or <Fem />.
- Words ending in <InlinePs opts={opts} ps={{ p: "ـه", f: "u" }} /> can also be <Fem /> plural, as in <InlinePs opts={opts} ps={{ p: "اوبه", f: "oobu", e: "water" }} /> - Words ending in <InlinePs opts={opts} ps={{ p: "ـه", f: "u" }} /> can also be <Fem /> plural, as in <InlinePs opts={opts} ps={{ p: "اوبه", f: "oobu", e: "water" }} />
<GenderGame level={1} /> <GameDisplay record={nounGenderGame1} />
## Exceptions ## Exceptions
@ -164,4 +166,4 @@ Some words are used to describe people who obviously have a gender and they *tot
}, },
]} /> ]} />
<GenderGame level={2} /> <GameDisplay record={nounGenderGame2} />

View File

@ -10,7 +10,8 @@ import {
import Table from "../../components/Table"; import Table from "../../components/Table";
import Link from "../../components/Link"; import Link from "../../components/Link";
import GenderTable from "../../components/GenderTable"; import GenderTable from "../../components/GenderTable";
import UnisexNounGame from "../../games/UnisexNounGame"; import { unisexNounGame } from "../../games/games";
import GameDisplay from "../../games/GameDisplay";
There are many words for people and animals in Pashto that can be used in both masculine and feminine forms. There are many words for people and animals in Pashto that can be used in both masculine and feminine forms.
@ -209,7 +210,7 @@ If the accent comes on the end of the word, the femine form is a little differen
} }
]} /> ]} />
<UnisexNounGame /> <GameDisplay record={unisexNounGame} />
<!-- <!--
{ {

View File

@ -6,7 +6,7 @@ import {
defaultTextOptions as opts, defaultTextOptions as opts,
Examples, Examples,
InlinePs, InlinePs,
removeFVariants, removeFVarients,
ConjugationViewer, ConjugationViewer,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
import cousins from "./cousins.png"; import cousins from "./cousins.png";
@ -42,7 +42,7 @@ This is used to talk about something happening in the future, while thinking of
<Carousel stickyTitle items={shuffleArray(basicVerbs)} render={(item) => { <Carousel stickyTitle items={shuffleArray(basicVerbs)} render={(item) => {
return { return {
title: <InlinePs opts={opts} ps={{ title: <InlinePs opts={opts} ps={{
...removeFVariants(item.entry), ...removeFVarients(item.entry),
e: item.def, e: item.def,
}} />, }} />,
body: <div style={{ textAlign: "left" }}> body: <div style={{ textAlign: "left" }}>
@ -74,7 +74,7 @@ This is used to talk about something happening in the future, while thinking of
<Carousel stickyTitle items={shuffleArray(basicVerbs)} render={(item) => { <Carousel stickyTitle items={shuffleArray(basicVerbs)} render={(item) => {
return { return {
title: <InlinePs opts={opts} ps={{ title: <InlinePs opts={opts} ps={{
...removeFVariants(item.entry), ...removeFVarients(item.entry),
e: item.def, e: item.def,
}} />, }} />,
body: <div style={{ textAlign: "left" }}> body: <div style={{ textAlign: "left" }}>

View File

@ -6,7 +6,7 @@ import {
defaultTextOptions as opts, defaultTextOptions as opts,
Examples, Examples,
InlinePs, InlinePs,
removeFVariants, removeFVarients,
ConjugationViewer, ConjugationViewer,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
import psmd from "../../lib/psmd"; import psmd from "../../lib/psmd";
@ -54,7 +54,7 @@ The <i class="fas fa-camera" /> **perfective imperative** is used when you want
<Carousel stickyTitle items={shuffleArray(basicVerbs)} render={(item) => { <Carousel stickyTitle items={shuffleArray(basicVerbs)} render={(item) => {
return { return {
title: <InlinePs opts={opts} ps={{ title: <InlinePs opts={opts} ps={{
...removeFVariants(item.entry), ...removeFVarients(item.entry),
e: item.def, e: item.def,
}} />, }} />,
body: <div className="text-left"> body: <div className="text-left">

View File

@ -6,7 +6,7 @@ import {
defaultTextOptions as opts, defaultTextOptions as opts,
Examples, Examples,
InlinePs, InlinePs,
removeFVariants, removeFVarients,
ConjugationViewer, ConjugationViewer,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
import psmd from "../../lib/psmd"; import psmd from "../../lib/psmd";
@ -38,7 +38,7 @@ The <Link to="/verbs/verb-endings/">present ending</Link> will change according
<Carousel stickyTitle items={shuffleArray(basicVerbs)} render={(item) => { <Carousel stickyTitle items={shuffleArray(basicVerbs)} render={(item) => {
return { return {
title: <InlinePs opts={opts} ps={{ title: <InlinePs opts={opts} ps={{
...removeFVariants(item.entry), ...removeFVarients(item.entry),
e: item.def, e: item.def,
}} />, }} />,
body: <div className="text-left"> body: <div className="text-left">

View File

@ -21,7 +21,7 @@ import {
grammarUnits, grammarUnits,
RootsAndStems, RootsAndStems,
getVerbInfo, getVerbInfo,
removeFVariants, removeFVarients,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
import shuffle from "../../lib/shuffle-array"; import shuffle from "../../lib/shuffle-array";
import Carousel from "../../components/Carousel"; import Carousel from "../../components/Carousel";
@ -44,7 +44,7 @@ export function InfoCarousel({ items, highlighted, hidePastParticiple }) {
: inf; : inf;
return { return {
title: <InlinePs opts={opts} ps={{ title: <InlinePs opts={opts} ps={{
...removeFVariants(item.entry), ...removeFVarients(item.entry),
e: item.def, e: item.def,
}} />, }} />,
body: <RootsAndStems body: <RootsAndStems

View File

@ -6,7 +6,7 @@ import {
defaultTextOptions as opts, defaultTextOptions as opts,
Examples, Examples,
InlinePs, InlinePs,
removeFVariants, removeFVarients,
ConjugationViewer, ConjugationViewer,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
import cousins from "./cousins.png"; import cousins from "./cousins.png";
@ -58,7 +58,7 @@ The subjunctive is made the same way as its cousin the <Link to="/verbs/present-
<Carousel stickyTitle items={shuffleArray(basicVerbs)} render={(item) => { <Carousel stickyTitle items={shuffleArray(basicVerbs)} render={(item) => {
return { return {
title: <InlinePs opts={opts} ps={{ title: <InlinePs opts={opts} ps={{
...removeFVariants(item.entry), ...removeFVarients(item.entry),
e: item.def, e: item.def,
}} />, }} />,
body: <div className="text-left"> body: <div className="text-left">

View File

@ -2,14 +2,27 @@ import React, { useState, useRef } from "react";
import { CountdownCircleTimer } from "react-countdown-circle-timer"; import { CountdownCircleTimer } from "react-countdown-circle-timer";
import Reward, { RewardElement } from 'react-rewards'; import Reward, { RewardElement } from 'react-rewards';
import Link from "../components/Link"; import Link from "../components/Link";
import { useUser } from "../user-context";
import "./timer.css"; import "./timer.css";
import { import {
getPercentageDone, getPercentageDone,
} from "../lib/game-utils"; } from "../lib/game-utils";
import {
Types as T,
} from "@lingdocs/pashto-inflector";
const errorVibration = 200; const errorVibration = 200;
function Game<T>({ questions, Display, timeLimit, Instructions, studyLink, label }: GameInput<T>) { function GameCore<T>({ questions, Display, timeLimit, Instructions, studyLink, id }:{
id: string,
studyLink: string,
Instructions: (props: { opts?: T.TextOptions }) => JSX.Element,
questions: () => QuestionGenerator<T>,
Display: (props: QuestionDisplayProps<T>) => JSX.Element,
timeLimit: number;
}) {
// TODO: report pass with id to user info
const rewardRef = useRef<RewardElement | null>(null); const rewardRef = useRef<RewardElement | null>(null);
const { user } = useUser();
const [finish, setFinish] = useState<null | "pass" | "fail" | "time out">(null); const [finish, setFinish] = useState<null | "pass" | "fail" | "time out">(null);
const [current, setCurrent] = useState<Current<T> | undefined>(undefined); const [current, setCurrent] = useState<Current<T> | undefined>(undefined);
const [questionBox, setQuestionBox] = useState<QuestionGenerator<T>>(questions()); const [questionBox, setQuestionBox] = useState<QuestionGenerator<T>>(questions());
@ -30,10 +43,17 @@ function Game<T>({ questions, Display, timeLimit, Instructions, studyLink, label
else setCurrent(next.value); else setCurrent(next.value);
} }
function handleFinish() { function handleFinish() {
// post results if (user) {
// TODO: post results
console.log(
"will post results for",
user.userId,
"results id",
id,
);
}
setFinish("pass"); setFinish("pass");
rewardRef.current?.rewardMe(); rewardRef.current?.rewardMe();
setCurrent(undefined);
} }
function handleQuit() { function handleQuit() {
setFinish(null); setFinish(null);
@ -66,8 +86,8 @@ function Game<T>({ questions, Display, timeLimit, Instructions, studyLink, label
: finish === "fail" : finish === "fail"
? "danger" ? "danger"
: "primary"; : "primary";
console.log("user is", user)
return <div> return <div>
<h4 className="my-4"><span role="img" aria-label="">🎮</span> {label}</h4>
<div className="text-center" style={{ minHeight: "200px" }}> <div className="text-center" style={{ minHeight: "200px" }}>
<div className="progress" style={{ height: "5px" }}> <div className="progress" style={{ height: "5px" }}>
<div className={`progress-bar bg-${progressColor}`} role="progressbar" style={{ width: getProgressWidth() }} /> <div className={`progress-bar bg-${progressColor}`} role="progressbar" style={{ width: getProgressWidth() }} />
@ -141,4 +161,4 @@ function failMessage(progress: Progress | undefined, finish: "time out" | "fail"
: `⏳ Time's Up ${face}`; : `⏳ Time's Up ${face}`;
} }
export default Game; export default GameCore;

10
src/games/GameDisplay.tsx Normal file
View File

@ -0,0 +1,10 @@
import React from "react";
function GameDisplay({ record: { title, Game } }: { record: GameRecord }) {
return <div>
<h4 className="my-4"><span role="img" aria-label="">🎮</span> {title}</h4>
<Game />
</div>
}
export default GameDisplay;

40
src/games/games.tsx Normal file
View File

@ -0,0 +1,40 @@
import React from "react";
import GenderGame from "./sub-cores/GenderGame";
import UnisexNounGame from "./sub-cores/UnisexNounGame";
const unisexNounsId = "unisex-nouns-1";
const nounGender1Id = "gender-nouns-1";
const nounGender2Id = "gender-nouns-2";
export const unisexNounGame: GameRecord = {
title: "Changing genders on unisex nouns",
id: unisexNounsId,
Game: function() {
// TODO: Why won't this.id word here??!
return <UnisexNounGame id={unisexNounsId} />;
},
}
export const nounGenderGame1: GameRecord = {
title: "Identify Noun Genders - Level 1",
id: nounGender1Id,
Game: function() {
return <GenderGame id={nounGender1Id} level={1} />;
},
}
export const nounGenderGame2: GameRecord = {
title: "Identify Noun Genders - Level 1",
id: nounGender2Id,
Game: function() {
return <GenderGame id={nounGender2Id} level={2} />;
},
}
const games: GameRecord[] = [
unisexNounGame,
nounGenderGame1,
nounGenderGame2,
];
export default games;

View File

@ -2,18 +2,18 @@ import React from "react";
import { import {
getRandomFromList, getRandomFromList,
makeProgress, makeProgress,
} from "../lib/game-utils"; } from "../../lib/game-utils";
import genderColors from "../lib/gender-colors"; import genderColors from "../../lib/gender-colors";
import Game from "./Game"; import GameCore from "../GameCore";
import { import {
Types as T, Types as T,
Examples, Examples,
defaultTextOptions as opts, defaultTextOptions as opts,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
import words from "../words/nouns-adjs"; import words from "../../words/nouns-adjs";
import { import {
firstVariation, firstVariation,
} from "../lib/text-tools"; } from "../../lib/text-tools";
const genders: T.Gender[] = ["masc", "fem"]; const genders: T.Gender[] = ["masc", "fem"];
@ -50,7 +50,7 @@ const exceptions: Record<string, CategorySet> = {
const amount = 40; const amount = 40;
export default function({level}: { level: 1 | 2 }) { export default function({level, id}: { level: 1 | 2, id: string}) {
function* questions () { function* questions () {
const wordPool = {...types}; const wordPool = {...types};
const exceptionsPool = {...exceptions}; const exceptionsPool = {...exceptions};
@ -100,10 +100,10 @@ export default function({level}: { level: 1 | 2 }) {
</div> </div>
} }
return <Game return <GameCore
label={level === 1 ? "Choose the right gender - Level 1" : "Choose the right gender - Level 2"}
studyLink={level === 1 ? "/nouns/nouns-gender#gender-by-ending" : "/nouns/nouns-gender#exceptions"} studyLink={level === 1 ? "/nouns/nouns-gender#gender-by-ending" : "/nouns/nouns-gender#exceptions"}
questions={questions} questions={questions}
id={id}
Display={Display} Display={Display}
timeLimit={level === 1 ? 65 : 85} timeLimit={level === 1 ? 65 : 85}
Instructions={Instructions} Instructions={Instructions}

View File

@ -3,9 +3,9 @@ import {
getRandomFromList, getRandomFromList,
makeProgress, makeProgress,
compareF, compareF,
} from "../lib/game-utils"; } from "../../lib/game-utils";
import genderColors from "../lib/gender-colors"; import genderColors from "../../lib/gender-colors";
import Game from "./Game"; import GameCore from "../GameCore";
import { import {
Types as T, Types as T,
Examples, Examples,
@ -14,10 +14,10 @@ import {
standardizePashto, standardizePashto,
// pashtoConsonants, // pashtoConsonants,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
import words from "../words/nouns-adjs"; import words from "../../words/nouns-adjs";
import { import {
firstVariation, firstVariation,
} from "../lib/text-tools"; } from "../../lib/text-tools";
const nouns = words.filter((w) => w.category === "nouns-unisex").map(x => x.entry); const nouns = words.filter((w) => w.category === "nouns-unisex").map(x => x.entry);
// type NType = "consonant" | "eyUnstressed" | "eyStressed" | "pashtun" | "withu" // type NType = "consonant" | "eyUnstressed" | "eyStressed" | "pashtun" | "withu"
@ -34,7 +34,7 @@ const amount = 20;
type Question = { entry: T.DictionaryEntry, gender: T.Gender }; type Question = { entry: T.DictionaryEntry, gender: T.Gender };
export default function() { export default function({ id }: { id: string }) {
function* questions (): Generator<Current<Question>> { function* questions (): Generator<Current<Question>> {
let pool = [...nouns]; let pool = [...nouns];
for (let i = 0; i < amount; i++) { for (let i = 0; i < amount; i++) {
@ -61,19 +61,26 @@ export default function() {
return g === "masc" ? "fem" : "masc"; return g === "masc" ? "fem" : "masc";
} }
const [answer, setAnswer] = useState<string>(""); const [answer, setAnswer] = useState<string>("");
const inflected = inflectWord(question.entry) as T.UnisexInflections; const infOut = inflectWord(question.entry);
if (!infOut) return <div>WORD ERROR</div>;
const { inflections } = infOut;
if (!inflections) return <div>WORD ERROR</div>;
const givenGender = question.gender === "masc" ? "masculine" : "feminine"; const givenGender = question.gender === "masc" ? "masculine" : "feminine";
const requiredGender = question.gender === "fem" ? "masculine" : "feminine"; const requiredGender = question.gender === "fem" ? "masculine" : "feminine";
if (!inflected || !inflected.masc || !inflected.fem) { if (!("masc" in inflections ) || !("fem" in inflections)) {
return <div>WORD ERROR</div>; return <div>WORD ERROR</div>;
} }
function handleInput({ target: { value }}: React.ChangeEvent<HTMLInputElement>) { if (!inflections.masc || !inflections.fem) {
return <div>WORD ERROR</div>;
}
const handleInput = ({ target: { value }}: React.ChangeEvent<HTMLInputElement>) => {
setAnswer(value); setAnswer(value);
} }
function handleSubmit(e: React.FormEvent<HTMLFormElement>) { const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault(); e.preventDefault();
const given = standardizePashto(answer.trim()); const given = standardizePashto(answer.trim());
const correct = inflected[flipGender(question.gender)][0].some((ps) => ( // @ts-ignore
const correct = inflections[flipGender(question.gender)][0].some((ps: T.PsString) => (
(given === ps.p) || compareF(given, ps.f) (given === ps.p) || compareF(given, ps.f)
)); ));
if (correct) { if (correct) {
@ -86,7 +93,7 @@ export default function() {
<div className="pt-2 pb-1 mb-2" style={{ maxWidth: "300px", margin: "0 auto", backgroundColor: genderColors[question.gender === "masc" ? "m" : "f"]}}> <div className="pt-2 pb-1 mb-2" style={{ maxWidth: "300px", margin: "0 auto", backgroundColor: genderColors[question.gender === "masc" ? "m" : "f"]}}>
<Examples opts={opts}>{[ <Examples opts={opts}>{[
{ {
...inflected[question.gender][0][0], ...inflections[question.gender][0][0],
e: firstVariation(question.entry.e), e: firstVariation(question.entry.e),
} }
]}</Examples> ]}</Examples>
@ -119,10 +126,10 @@ export default function() {
</div> </div>
} }
return <Game return <GameCore
label="Changing genders on unisex nouns"
studyLink="/nouns/nouns-unisex#" studyLink="/nouns/nouns-unisex#"
questions={questions} questions={questions}
id={id}
Display={Display} Display={Display}
timeLimit={130} timeLimit={130}
Instructions={Instructions} Instructions={Instructions}

View File

@ -10,6 +10,7 @@ import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import App from './App'; import App from './App';
import { BrowserRouter as Router } from "react-router-dom"; import { BrowserRouter as Router } from "react-router-dom";
import { UserProvider} from "./user-context";
import * as serviceWorker from './serviceWorker'; import * as serviceWorker from './serviceWorker';
import "bootstrap/dist/css/bootstrap.min.css"; import "bootstrap/dist/css/bootstrap.min.css";
import "@fortawesome/fontawesome-free/css/all.css"; import "@fortawesome/fontawesome-free/css/all.css";
@ -17,7 +18,9 @@ import "@fortawesome/fontawesome-free/css/all.css";
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <React.StrictMode>
<Router> <Router>
<App /> <UserProvider>
<App />
</UserProvider>
</Router> </Router>
</React.StrictMode>, </React.StrictMode>,
document.getElementById('root') document.getElementById('root')

13
src/types.d.ts vendored
View File

@ -15,11 +15,8 @@ type QuestionDisplayProps<T> = {
callback: (correct: boolean) => void, callback: (correct: boolean) => void,
}; };
type GameInput<T> = { type GameRecord = {
label: string, title: string,
studyLink: string, id: string,
Instructions: (props: { opts?: import("@lingdocs/pashto-inflector").Types.TextOptions }) => JSX.Element, Game: () => JSX.Element,
questions: () => QuestionGenerator<T>, };
Display: (props: QuestionDisplayProps<T>) => JSX.Element,
timeLimit: number;
}

24
src/user-context.tsx Normal file
View File

@ -0,0 +1,24 @@
import React, { useState, createContext } from "react"
import { AT } from "@lingdocs/lingdocs-main";
const UserContext = createContext<
{ user: AT.LingdocsUser | undefined, setUser: React.Dispatch<React.SetStateAction<AT.LingdocsUser | undefined>> }
| undefined
>(undefined);
function UserProvider({ children }: any) {
const [user, setUser] = useState<AT.LingdocsUser | undefined>(undefined);
return <UserContext.Provider value={{ user, setUser }}>
{children}
</UserContext.Provider>;
}
function useUser() {
const context = React.useContext(UserContext)
if (context === undefined) {
throw new Error('useCount must be used within a CountProvider')
}
return context;
}
export { UserProvider, useUser };

130
yarn.lock
View File

@ -1566,10 +1566,19 @@
"@types/yargs" "^15.0.0" "@types/yargs" "^15.0.0"
chalk "^4.0.0" chalk "^4.0.0"
"@lingdocs/pashto-inflector@^0.9.3": "@lingdocs/lingdocs-main@^0.0.4":
version "0.9.6" version "0.0.4"
resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-0.9.6.tgz#c7b5fe2d0c253cdae48151f667b0248600603819" resolved "https://npm.lingdocs.com/@lingdocs%2flingdocs-main/-/lingdocs-main-0.0.4.tgz#7ca25f48e934f070d3c6048be1787dd8fb3133af"
integrity sha512-/fLCHUdRqCLO9bDDve59yQlRXNd+7gXOeD6aO+IKOBz2KhIzSk7KRctSdM1jfv2E356QU/JmVL/+o0EfdWI33Q== integrity sha512-6tegCbI7eeq43GIAspoAfGhkCXNbXgH/9immS+WljJ3188LIXFduMikwFbJZYVI7h3eUrOz1CYCB0qbdbLd0Vw==
dependencies:
passport-github2 "^0.1.12"
passport-google-oauth "^2.0.0"
passport-twitter "^1.0.4"
"@lingdocs/pashto-inflector@^1.0.5":
version "1.0.6"
resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-1.0.6.tgz#b61262c04916442a1023002bd7426ee39d77635f"
integrity sha512-yhijpCx1nBHnwykydOPOWzZlA388EioLr/SftNcYgRilxOjHVzXzEHL9dMNxciAiCNKFcNic2UVp+Tha4WEbSA==
dependencies: dependencies:
classnames "^2.2.6" classnames "^2.2.6"
pbf "^3.2.1" pbf "^3.2.1"
@ -1906,6 +1915,11 @@
dependencies: dependencies:
"@types/unist" "*" "@types/unist" "*"
"@types/history@*":
version "4.7.9"
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.9.tgz#1cfb6d60ef3822c589f18e70f8b12f9a28ce8724"
integrity sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==
"@types/invariant@^2.2.29": "@types/invariant@^2.2.29":
version "2.2.35" version "2.2.35"
resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.35.tgz#cd3ebf581a6557452735688d8daba6cf0bd5a3be" resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.35.tgz#cd3ebf581a6557452735688d8daba6cf0bd5a3be"
@ -2022,6 +2036,23 @@
dependencies: dependencies:
"@types/react" "*" "@types/react" "*"
"@types/react-router-dom@^5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.1.9.tgz#e8a8f687351ecc8c68bb4161d7e4b9df4994416e"
integrity sha512-Go0vxZSigXTyXx8xPkGiBrrc3YbBs82KE14WENMLS6TSUKcRFSmYVbL19zFOnNFqJhqrPqEs2h5eUpJhSRrwZw==
dependencies:
"@types/history" "*"
"@types/react" "*"
"@types/react-router" "*"
"@types/react-router@*":
version "5.1.16"
resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.16.tgz#f3ba045fb96634e38b21531c482f9aeb37608a99"
integrity sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg==
dependencies:
"@types/history" "*"
"@types/react" "*"
"@types/react-transition-group@^4.4.1": "@types/react-transition-group@^4.4.1":
version "4.4.1" version "4.4.1"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.1.tgz#e1a3cb278df7f47f17b5082b1b3da17170bd44b1" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.1.tgz#e1a3cb278df7f47f17b5082b1b3da17170bd44b1"
@ -2883,6 +2914,11 @@ base64-js@^1.0.2:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
base64url@3.x.x:
version "3.0.1"
resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d"
integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==
base@^0.11.1: base@^0.11.1:
version "0.11.2" version "0.11.2"
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
@ -8106,6 +8142,11 @@ oauth-sign@~0.9.0:
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
oauth@0.9.x:
version "0.9.15"
resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1"
integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE=
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@ -8521,6 +8562,68 @@ pascalcase@^0.1.1:
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
passport-github2@^0.1.12:
version "0.1.12"
resolved "https://registry.yarnpkg.com/passport-github2/-/passport-github2-0.1.12.tgz#a72ebff4fa52a35bc2c71122dcf470d1116f772c"
integrity sha512-3nPUCc7ttF/3HSP/k9sAXjz3SkGv5Nki84I05kSQPo01Jqq1NzJACgMblCK0fGcv9pKCG/KXU3AJRDGLqHLoIw==
dependencies:
passport-oauth2 "1.x.x"
passport-google-oauth1@1.x.x:
version "1.0.0"
resolved "https://registry.yarnpkg.com/passport-google-oauth1/-/passport-google-oauth1-1.0.0.tgz#af74a803df51ec646f66a44d82282be6f108e0cc"
integrity sha1-r3SoA99R7GRvZqRNgigr5vEI4Mw=
dependencies:
passport-oauth1 "1.x.x"
passport-google-oauth20@2.x.x:
version "2.0.0"
resolved "https://registry.yarnpkg.com/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz#0d241b2d21ebd3dc7f2b60669ec4d587e3a674ef"
integrity sha512-KSk6IJ15RoxuGq7D1UKK/8qKhNfzbLeLrG3gkLZ7p4A6DBCcv7xpyQwuXtWdpyR0+E0mwkpjY1VfPOhxQrKzdQ==
dependencies:
passport-oauth2 "1.x.x"
passport-google-oauth@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/passport-google-oauth/-/passport-google-oauth-2.0.0.tgz#f6eb4bc96dd6c16ec0ecfdf4e05ec48ca54d4dae"
integrity sha512-JKxZpBx6wBQXX1/a1s7VmdBgwOugohH+IxCy84aPTZNq/iIPX6u7Mqov1zY7MKRz3niFPol0KJz8zPLBoHKtYA==
dependencies:
passport-google-oauth1 "1.x.x"
passport-google-oauth20 "2.x.x"
passport-oauth1@1.x.x:
version "1.2.0"
resolved "https://registry.yarnpkg.com/passport-oauth1/-/passport-oauth1-1.2.0.tgz#5229d431781bf5b265bec86ce9a9cce58a756cf9"
integrity sha512-Sv2YWodC6jN12M/OXwmR4BIXeeIHjjbwYTQw4kS6tHK4zYzSEpxBgSJJnknBjICA5cj0ju3FSnG1XmHgIhYnLg==
dependencies:
oauth "0.9.x"
passport-strategy "1.x.x"
utils-merge "1.x.x"
passport-oauth2@1.x.x:
version "1.6.0"
resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.6.0.tgz#5f599735e0ea40ea3027643785f81a3a9b4feb50"
integrity sha512-emXPLqLcVEcLFR/QvQXZcwLmfK8e9CqvMgmOFJxcNT3okSFMtUbRRKpY20x5euD+01uHsjjCa07DYboEeLXYiw==
dependencies:
base64url "3.x.x"
oauth "0.9.x"
passport-strategy "1.x.x"
uid2 "0.0.x"
utils-merge "1.x.x"
passport-strategy@1.x.x:
version "1.0.0"
resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
integrity sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=
passport-twitter@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/passport-twitter/-/passport-twitter-1.0.4.tgz#01a799e1f760bf2de49f2ba5fba32282f18932d7"
integrity sha1-AaeZ4fdgvy3knyul+6MigvGJMtc=
dependencies:
passport-oauth1 "1.x.x"
xtraverse "0.1.x"
path-browserify@0.0.1: path-browserify@0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
@ -11792,6 +11895,11 @@ typographic-quotes@^1.2.1:
dependencies: dependencies:
typographic-quotes-l10n-db "^1.0.0" typographic-quotes-l10n-db "^1.0.0"
uid2@0.0.x:
version "0.0.4"
resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.4.tgz#033f3b1d5d32505f5ce5f888b9f3b667123c0a44"
integrity sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==
uncontrollable@^7.0.0, uncontrollable@^7.2.1: uncontrollable@^7.0.0, uncontrollable@^7.2.1:
version "7.2.1" version "7.2.1"
resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-7.2.1.tgz#1fa70ba0c57a14d5f78905d533cf63916dc75738" resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-7.2.1.tgz#1fa70ba0c57a14d5f78905d533cf63916dc75738"
@ -12123,7 +12231,7 @@ utila@^0.4.0, utila@~0.4:
resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=
utils-merge@1.0.1: utils-merge@1.0.1, utils-merge@1.x.x:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
@ -12674,6 +12782,11 @@ xmlchars@^2.1.1:
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
xmldom@0.1.x:
version "0.1.31"
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
xregexp@^4.3.0: xregexp@^4.3.0:
version "4.3.0" version "4.3.0"
resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.3.0.tgz#7e92e73d9174a99a59743f67a4ce879a04b5ae50" resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.3.0.tgz#7e92e73d9174a99a59743f67a4ce879a04b5ae50"
@ -12686,6 +12799,13 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
xtraverse@0.1.x:
version "0.1.0"
resolved "https://registry.yarnpkg.com/xtraverse/-/xtraverse-0.1.0.tgz#b741bad018ef78d8a9d2e83ade007b3f7959c732"
integrity sha1-t0G60BjveNip0ug63gB7P3lZxzI=
dependencies:
xmldom "0.1.x"
y18n@^4.0.0: y18n@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"