This commit is contained in:
lingdocs 2022-05-17 15:03:59 -05:00
parent 0ce7775093
commit 3e1d6d0cea
33 changed files with 277 additions and 176 deletions

View File

@ -79,9 +79,12 @@ const editor: AT.LingdocsUser = {
},
};
export default {
// @ts-ignore
const users: any = {
basic,
student,
editor,
admin,
};
export default users;

View File

@ -20,6 +20,7 @@ export declare type EmailVerified = true | Hash | false;
export declare type ActionComplete = {
ok: true;
message: string;
tests?: TestResult[];
};
export declare type ActionError = {
ok: false;
@ -48,6 +49,11 @@ export declare type UserTextOptionsRecord = {
lastModified: TimeStamp;
userTextOptions: UserTextOptions;
};
export declare type TestResult = {
done: true;
time: TimeStamp;
id: string;
};
export declare type LingdocsUser = {
userId: UUID;
admin?: boolean;
@ -63,7 +69,7 @@ export declare type LingdocsUser = {
requestedOn: TimeStamp;
};
upgradeToStudentRequest?: "waiting" | "denied";
tests: [];
tests: TestResult[];
lastLogin: TimeStamp;
lastActive: TimeStamp;
userTextOptionsRecord: undefined | UserTextOptionsRecord;
@ -88,6 +94,14 @@ export declare type UpgradeUserResponse = {
message: "user already upgraded" | "user upgraded to student";
user: LingdocsUser;
};
export declare type PostTestResultsBody = {
tests: TestResult[];
};
export declare type PostTestResultsResponse = {
ok: true;
message: "posted test results";
tests: TestResult[];
};
export declare type UpdateUserTextOptionsRecordBody = {
userTextOptionsRecord: UserTextOptionsRecord;
};

View File

@ -1,5 +1,6 @@
import * as AT from "./website/src/types/account-types";
import * as FT from "./website/src/types/functions-types";
import * as DT from "./website/src/types/dictionary-types";
import {
getTimestamp,
} from "./account/src/lib/time-utils";
@ -54,4 +55,5 @@ export {
// TYPES
AT,
FT,
DT,
};

View File

@ -1,6 +1,6 @@
{
"name": "@lingdocs/lingdocs-main",
"version": "0.2.8",
"version": "0.2.9",
"description": "types and functions for lingdocs stuff",
"main": "dist/library.js",
"module": "dist/library.js",

View File

@ -74,6 +74,12 @@ import classNames from "classnames";
import { getTextOptions } from "./lib/get-text-options";
import { getTextFromShareTarget } from "./lib/share-target";
import { objIsEqual, userObjIsEqual } from "./lib/misc-helpers";
import {
State,
TextOptionsRecord,
TextOptionsAction,
OptionsAction,
} from "./types/dictionary-types";
// to allow Moustrap key combos even when input fields are in focus
Mousetrap.prototype.stopCallback = function () {

View File

@ -10,6 +10,7 @@ import { useEffect, useState } from "react";
import {
getAudioAttachment,
} from "../lib/wordlist-database";
import { WordlistWord } from "../types/dictionary-types";
export function AudioPlayButton({ word }: { word: WordlistWord }) {
const [src, setSrc] = useState<string | undefined>(undefined);

View File

@ -6,6 +6,8 @@
*
*/
import { DictionaryStatus } from "../types/dictionary-types";
function DictionaryStatusDisplay({ status }: { status: DictionaryStatus }) {
if (status === "loading" || status === "updating") {
return (

View File

@ -12,6 +12,7 @@ import {
updateWordlistWord,
} from "../lib/wordlist-database";
import WordlistImage from "./WordlistImage";
import { WordlistWord } from "../types/dictionary-types";
// TODO: !! remember to save the new dimensions whenever modifying the image

View File

@ -14,6 +14,10 @@ import {
displayFormResult,
displayPositionResult,
} from "../lib/inflection-search-helpers";
import {
InflectionSearchResult,
InflectionName,
} from "../types/dictionary-types";
function InflectionSearchResult(
{ result, textOptions, entry }:

View File

@ -7,6 +7,12 @@
*/
import { useRef } from "react";
import { State } from "../types/dictionary-types";
import {
OptionsAction,
Language,
SearchType,
} from "../types/dictionary-types";
const SearchBar = ({ state, optionsDispatch, handleSearchValueChange, onBottom }: {
state: State

View File

@ -1,5 +1,6 @@
import { useState, useEffect } from "react";
import { getImageAttachment } from "../lib/wordlist-database";
import { WordlistWord } from "../types/dictionary-types";
function WordlistImage({ word }: { word: WordlistWord }) {
const [imgSrc, setImgSrc] = useState<string | undefined>(undefined);

View File

@ -14,6 +14,7 @@ import {
updateWordlistWord,
hasAttachment,
} from "../lib/wordlist-database";
import { WordlistWord } from "../types/dictionary-types";
const droppingStyle = {
boxShadow: "0 0 5px rgba(81, 203, 238, 1)",

View File

@ -2,6 +2,7 @@ import { Types as T } from "@lingdocs/pashto-inflector";
import { dictionary } from "../dictionary";
import { baseSupermemo } from "../spaced-repetition";
import { refreshWordlist } from "./pouch-dbs";
import { WordlistWord } from "../../types/dictionary-types";
let wordlistDb: {
name: string,

View File

@ -10,6 +10,7 @@ import {
addToAttachmentObject,
removeAttachmentFromObject,
} from "./wordlist-database";
import { WordlistWord, WordlistWordWAttachments } from "../types/dictionary-types";
export function addAudioToWordlistWord(word: WordlistWord, file: File): WordlistWord {
return {

View File

@ -21,6 +21,10 @@ import { fuzzifyPashto } from "./fuzzify-pashto/fuzzify-pashto";
import relevancy from "relevancy";
import { makeAWeeBitFuzzy } from "./wee-bit-fuzzy";
import { getTextOptions } from "./get-text-options";
import {
DictionaryAPI,
State,
} from "../types/dictionary-types";
// const dictionaryBaseUrl = "https://storage.googleapis.com/lingdocs/";
const dictionaryUrl = `https://storage.googleapis.com/lingdocs/dictionary`;
@ -31,22 +35,6 @@ const dictionaryCollectionName = "dictionary3";
// const dictionaryDatabaseName = "dictdb.db";
export const pageSize = 35;
export type DictionaryAPI = {
initialize: () => Promise<{
response: "loaded first time" | "loaded from saved",
dictionaryInfo: T.DictionaryInfo,
}>,
update: (updateComing: () => void) => Promise<{
response: "no need for update" | "updated" | "unable to check",
dictionaryInfo: T.DictionaryInfo,
}>,
search: (state: State) => T.DictionaryEntry[],
exactPashtoSearch: (search: string) => T.DictionaryEntry[],
getNewWordsThisMonth: () => T.DictionaryEntry[],
findOneByTs: (ts: number) => T.DictionaryEntry | undefined,
findRelatedEntries: (entry: T.DictionaryEntry) => T.DictionaryEntry[],
}
const relevancySorter = new relevancy.Sorter();
const db = indexedDB.open('inPrivate');

View File

@ -1,4 +1,7 @@
import { Types as T } from "@lingdocs/pashto-inflector";
import {
State,
} from "../types/dictionary-types";
export function getTextOptions(state: State): T.TextOptions {
return state.options.textOptionsRecord.textOptions;

View File

@ -2,6 +2,7 @@ import Resizer from "react-image-file-resizer";
import {
addToAttachmentObject, removeAttachmentFromObject,
} from "./wordlist-database";
import { WordlistWord, WordlistWordWAttachments, AttachmentWithData } from "../types/dictionary-types";
const maxImgSize = {
width: 1200,

View File

@ -7,6 +7,7 @@
*/
import * as AT from "../types/account-types";
import { Options } from "../types/dictionary-types";
export const optionsLocalStorageName = "options3";
export const userLocalStorageName = "user1";

View File

@ -1,5 +1,11 @@
import { Types as IT } from "@lingdocs/pashto-inflector";
import * as AT from "../types/account-types";
import {
Options,
OptionsAction,
TextOptionsAction,
TextOptionsRecord,
} from "../types/dictionary-types";
export function optionsReducer(options: Options, action: OptionsAction): Options {
if (action.type === "toggleLanguage") {

View File

@ -1,6 +1,10 @@
import PouchDB from "pouchdb";
import * as AT from "../types/account-types";
import * as FT from "../types/functions-types";
import {
WordlistWord,
WordlistWordDoc,
} from "../types/dictionary-types";
type LocalDbType = "submissions" | "wordlist" | "reviewTasks";

View File

@ -10,6 +10,9 @@ import {
getVerbInfo,
} from "@lingdocs/pashto-inflector";
import { isPashtoScript } from "./is-pashto";
import {
InflectionSearchResult,
} from "../types/dictionary-types";
// 1st iteration: Brute force make every single conjugation and check all - 5300ms
// 2nd iteration: Check if it makes a big difference to search via function - 5100ms

View File

@ -14,6 +14,11 @@ import {
isPluralInflectionSet,
} from "@lingdocs/pashto-inflector";
import { personFromVerbBlockPos } from "@lingdocs/pashto-inflector";
import {
InflectionName,
PluralInflectionName,
InflectionSearchResult,
} from "../types/dictionary-types";
const inflectionNames: { inflections: InflectionName[], plural: PluralInflectionName[] } = {
inflections: ["plain", "1st", "2nd"],

View File

@ -15,6 +15,9 @@ import dayjs from "dayjs";
import {
getMillisecondsPeriod,
} from "./time-utils";
import {
WordlistWord,
} from "../types/dictionary-types";
/* starting stage of review, based on Pimseleur intervals */
const warmupIntervals = [

View File

@ -26,6 +26,12 @@ import {
prepBase64,
} from "./image-tools";
import { getMillisecondsPeriod } from "./time-utils";
import {
WordlistWord,
AttachmentType,
Attachments,
AttachmentToPut,
} from "../types/dictionary-types";
export async function addToWordlist({ entry, notes }: {
entry: T.DictionaryEntry,
@ -79,6 +85,7 @@ export async function getWordlistCsv(sortType: "alphabetical" | "time"): Promise
[w.entry.p, w.entry.f, w.entry.c, w.entry.e]
));
if (sortType === "alphabetical") {
// @ts-ignore
forCsv.sort((a, b) => a[0].localeCompare(b[0], "ps"));
}
const csv = Papa.unparse(forCsv);

View File

@ -8,6 +8,7 @@
import { Helmet } from "react-helmet";
import dayjs from "dayjs";
import { State } from "../types/dictionary-types";
const About = ({ state } : { state: State }) => (
<div className="width-limiter">

View File

@ -11,7 +11,6 @@ import classNames from "classnames";
import { Link } from "react-router-dom";
import { VPExplorer } from "@lingdocs/pashto-inflector";
import { entryFeeder } from "../lib/dictionary";
import { DictionaryAPI } from "../lib/dictionary";
import {
ConjugationViewer,
InflectionsTable,
@ -30,6 +29,7 @@ import {
import { Helmet } from "react-helmet";
import { TextOptions } from "@lingdocs/pashto-inflector/dist/types";
import * as AT from "../types/account-types";
import { DictionaryAPI } from "../types/dictionary-types";
const textFields: {field: T.DictionaryEntryTextField, label: string}[] = [
{ field: "p", label: "Pashto" },

View File

@ -35,8 +35,11 @@ import { Modal } from "react-bootstrap";
import { getTextOptions } from "../lib/get-text-options";
import {
entryFeeder,
DictionaryAPI,
} from "../lib/dictionary";
import {
State,
DictionaryAPI,
} from "../types/dictionary-types";
function IsolatedEntry({ state, dictionary, isolateEntry }: {
state: State,

View File

@ -11,6 +11,15 @@ import {
} from "@lingdocs/pashto-inflector";
import { Helmet } from "react-helmet";
import { wordlistEnabled } from "../lib/level-management";
import {
State,
Options,
PTextSize,
SearchBarPosition,
Theme,
OptionsAction,
TextOptionsAction,
} from "../types/dictionary-types";
const fontSizeOptions: {
label: string,

View File

@ -21,9 +21,13 @@ import {
Types as T,
revertSpelling,
} from "@lingdocs/pashto-inflector";
import InflectionSearchResult from "../components/InflectionSearchResult";
import InflectionSearchResultDisplay from "../components/InflectionSearchResult";
import { searchAllInflections } from "../lib/search-all-inflections";
import { getTextOptions } from "../lib/get-text-options";
import {
State,
InflectionSearchResult,
} from "../types/dictionary-types";
const inflectionSearchIcon = "fas fa-search-plus";
@ -125,7 +129,7 @@ function Results({ state, isolateEntry }: {
/>
<div className="mb-3 ml-2">
{p.results.map((result: InflectionSearchResult, i) => (
<InflectionSearchResult
<InflectionSearchResultDisplay
key={"inf-result" + i}
textOptions={textOptions}
result={result}

View File

@ -9,6 +9,9 @@ import {
} from "@lingdocs/pashto-inflector";
import { Helmet } from "react-helmet";
import { getTextOptions } from "../lib/get-text-options";
import {
State,
} from "../types/dictionary-types";
function ReviewTask({ reviewTask, textOptions }: { reviewTask: FT.ReviewTask, textOptions: T.TextOptions }) {
function handleDelete() {

View File

@ -44,6 +44,13 @@ import AudioPlayButton from "../components/AudioPlayButton";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime.js";
import hitBottom from "../lib/hitBottom";
import {
Options,
WordlistWord,
Language,
OptionsAction,
WordlistMode,
} from "../types/dictionary-types";
const cleanupIcon = "broom";

153
website/src/types.d.ts vendored
View File

@ -1,153 +0,0 @@
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
type DictionaryStatus = "loading" | "ready" | "updating" | "error loading";
type Language = "Pashto" | "English";
type SearchType = "alphabetical" | "fuzzy";
type Theme = "light" | "dark";
type PTextSize = "normal" | "larger" | "largest";
type Phonetics = "lingdocs" | "ipa" | "alalc" | "none";
type Dialect = "standard" | "peshawer" | "southern";
type SearchBarPosition = "top" | "bottom";
type WordlistMode = "browse" | "review";
type TextOptionsRecord = {
lastModified: import("./types/account-types").TimeStamp,
textOptions: import("@lingdocs/pashto-inflector").Types.TextOptions,
};
type Options = {
language: Language,
searchType: SearchType,
theme: Theme,
textOptionsRecord: TextOptionsRecord,
wordlistMode: WordlistMode,
wordlistReviewLanguage: Language,
wordlistReviewBadge: boolean,
searchBarPosition: SearchBarPosition,
}
type UserLevel = "basic" | "student" | "editor";
type State = {
dictionaryStatus: DictionaryStatus,
searchValue: string,
options: Options,
page: number,
isolatedEntry: import("@lingdocs/pashto-inflector").Types.DictionaryEntry | undefined,
results: import("@lingdocs/pashto-inflector").Types.DictionaryEntry[],
wordlist: WordlistWord[],
reviewTasks: import("./types/functions-types").ReviewTask[],
dictionaryInfo: import("@lingdocs/pashto-inflector").Types.DictionaryInfo | undefined,
user: undefined | AT.LingdocsUser,
}
type OptionsAction = {
type: "toggleSearchType",
} | {
type: "toggleLanguage",
} | {
type: "changeTheme",
payload: Theme,
} | {
type: "changeSearchBarPosition",
payload: SearchBarPosition,
} | {
type: "changeUserLevel",
payload: UserLevel,
} | {
type: "changeWordlistMode",
payload: WordlistMode,
} | {
type: "changeWordlistReviewLanguage",
payload: Language,
} | {
type: "changeWordlistReviewBadge",
payload: boolean,
} | {
type: "updateTextOptionsRecord",
payload: TextOptionsRecord,
};
type TextOptionsAction = {
type: "changePTextSize",
payload: PTextSize,
} | {
type: "changeSpelling",
payload: import("@lingdocs/pashto-inflector").Types.Spelling,
} | {
type: "changePhonetics",
payload: import("@lingdocs/pashto-inflector").Types.Phonetics,
} | {
type: "changeDialect",
payload: import("@lingdocs/pashto-inflector").Types.Dialect,
} | {
type: "changeDiacritics",
payload: boolean,
};
type AttachmentToPut = {
content_type: string,
data: string | blob,
}
type AttachmentWithData = {
content_type: string,
digest: string,
data: string | blob,
}
type AttachmentWOutData = {
content_type: string,
digest: string,
stub: true;
}
type Attachment = AttachmentToPut | AttachmentWithData | AttachmentWOutData
type AttachmentType = "image" | "audio";
type Attachments = {
/* only allows one image and one audio attachment - max 2 values */
[filename: string]: Attachment,
};
type WordlistWordBase = {
_id: string,
/* a backup copy of the full dictionary entry in case it gets deleted from the dictionary */
entry: T.DictionaryEntry,
/* the notes/context provided by the user for the word in their wordlist */
notes: string,
supermemo: import("supermemo").SuperMemoItem,
/* rep/stage of warmup stage before moving into supermemo mode */
warmup: number | "done",
/* date due for review - ISO string */
dueDate: number,
}
type WordlistAttachmentInfo = {
imgSize?: { height: number, width: number },
_attachments: Attachments,
}
type WordlistWordWAttachments = WordlistWordBase & WordlistAttachmentInfo;
type WordlistWord = WordlistWordBase | WordlistWordWAttachments;
type WordlistWordDoc = WordlistWord & { _rev: string, _id: string };
type InflectionName = "plain" | "1st" | "2nd";
type PluralInflectionName = "plural" | "2nd";
type InflectionSearchResult = {
form: string[],
matches: {
ps: T.PsString,
pos: InflectionName[] | import("@lingdocs/pashto-inflector").Types.Person[] | null,
}[],
};

View File

@ -0,0 +1,163 @@
export type DictionaryStatus = "loading" | "ready" | "updating" | "error loading";
export type State = {
dictionaryStatus: DictionaryStatus,
searchValue: string,
options: Options,
page: number,
isolatedEntry: import("@lingdocs/pashto-inflector").Types.DictionaryEntry | undefined,
results: import("@lingdocs/pashto-inflector").Types.DictionaryEntry[],
wordlist: WordlistWord[],
reviewTasks: import("./functions-types").ReviewTask[],
dictionaryInfo: import("@lingdocs/pashto-inflector").Types.DictionaryInfo | undefined,
user: undefined | import("./account-types").LingdocsUser,
}
export type DictionaryAPI = {
initialize: () => Promise<{
response: "loaded first time" | "loaded from saved",
dictionaryInfo: import("@lingdocs/pashto-inflector").Types.DictionaryInfo,
}>,
update: (updateComing: () => void) => Promise<{
response: "no need for update" | "updated" | "unable to check",
dictionaryInfo: import("@lingdocs/pashto-inflector").Types.DictionaryInfo,
}>,
search: (state: State) => import("@lingdocs/pashto-inflector").Types.DictionaryEntry[],
exactPashtoSearch: (search: string) => import("@lingdocs/pashto-inflector").Types.DictionaryEntry[],
getNewWordsThisMonth: () => import("@lingdocs/pashto-inflector").Types.DictionaryEntry[],
findOneByTs: (ts: number) => import("@lingdocs/pashto-inflector").Types.DictionaryEntry | undefined,
findRelatedEntries: (entry: import("@lingdocs/pashto-inflector").Types.DictionaryEntry) => import("@lingdocs/pashto-inflector").Types.DictionaryEntry[],
}
export type WordlistWordBase = {
_id: string,
/* a backup copy of the full dictionary entry in case it gets deleted from the dictionary */
entry: import("@lingdocs/pashto-inflector").Types.DictionaryEntry,
/* the notes/context provided by the user for the word in their wordlist */
notes: string,
supermemo: import("supermemo").SuperMemoItem,
/* rep/stage of warmup stage before moving into supermemo mode */
warmup: number | "done",
/* date due for review - ISO string */
dueDate: number,
}
export type WordlistAttachmentInfo = {
imgSize?: { height: number, width: number },
_attachments: Attachments,
}
export type WordlistWordWAttachments = WordlistWordBase & WordlistAttachmentInfo;
export type WordlistWord = WordlistWordBase | WordlistWordWAttachments;
export type Options = {
language: Language,
searchType: SearchType,
theme: Theme,
textOptionsRecord: TextOptionsRecord,
wordlistMode: WordlistMode,
wordlistReviewLanguage: Language,
wordlistReviewBadge: boolean,
searchBarPosition: SearchBarPosition,
}
export type Language = "Pashto" | "English";
export type SearchType = "alphabetical" | "fuzzy";
export type Theme = "light" | "dark";
export type PTextSize = "normal" | "larger" | "largest";
export type Phonetics = "lingdocs" | "ipa" | "alalc" | "none";
export type Dialect = "standard" | "peshawer" | "southern";
export type SearchBarPosition = "top" | "bottom";
export type WordlistMode = "browse" | "review";
export type TextOptionsRecord = {
lastModified: import("./account-types").TimeStamp,
textOptions: import("@lingdocs/pashto-inflector").Types.TextOptions,
};
export type UserLevel = "basic" | "student" | "editor";
export type OptionsAction = {
type: "toggleSearchType",
} | {
type: "toggleLanguage",
} | {
type: "changeTheme",
payload: Theme,
} | {
type: "changeSearchBarPosition",
payload: SearchBarPosition,
} | {
type: "changeUserLevel",
payload: UserLevel,
} | {
type: "changeWordlistMode",
payload: WordlistMode,
} | {
type: "changeWordlistReviewLanguage",
payload: Language,
} | {
type: "changeWordlistReviewBadge",
payload: boolean,
} | {
type: "updateTextOptionsRecord",
payload: TextOptionsRecord,
};
export type TextOptionsAction = {
type: "changePTextSize",
payload: PTextSize,
} | {
type: "changeSpelling",
payload: import("@lingdocs/pashto-inflector").Types.Spelling,
} | {
type: "changePhonetics",
payload: "lingdocs" | "ipa" | "alalc" | "none",
} | {
type: "changeDialect",
payload: "standard" | "peshawer" | "southern",
} | {
type: "changeDiacritics",
payload: boolean,
};
export type AttachmentToPut = {
content_type: string,
data: string | Blob,
}
export type AttachmentWithData = {
content_type: string,
digest: string,
data: string | Blob,
}
export type AttachmentWOutData = {
content_type: string,
digest: string,
stub: true;
}
export type Attachment = AttachmentToPut | AttachmentWithData | AttachmentWOutData
export type AttachmentType = "image" | "audio";
export type Attachments = {
/* only allows one image and one audio attachment - max 2 values */
[filename: string]: Attachment,
};
export type WordlistWordDoc = WordlistWord & { _rev: string, _id: string };
export type InflectionName = "plain" | "1st" | "2nd";
export type PluralInflectionName = "plural" | "2nd";
export type InflectionSearchResult = {
form: string[],
matches: {
ps: import("@lingdocs/pashto-inflector").Types.PsString,
pos: InflectionName[] | import("@lingdocs/pashto-inflector").Types.Person[] | null,
}[],
};