From 485279151c9176ecc20a6510f12683a07ed035e6 Mon Sep 17 00:00:00 2001 From: Egor Gorbachev <7gorbachevm@gmail.com> Date: Mon, 29 Jan 2024 11:20:36 +0700 Subject: [PATCH] Formatting field switcher + CloudStorage adapter (#8) --- src/lib/cache/cache-promise.test.ts | 2 +- src/lib/mobx-form/persistable-field.ts | 3 +- src/lib/sanitize-html/remove-all-tags.ts | 5 +- src/lib/telegram/cloud-storage.ts | 42 +++++++++++++ .../{hapticNotification.ts => haptics.ts} | 0 src/lib/telegram/storage-adapter.ts | 6 ++ src/screens/deck-form/card-form-view.tsx | 63 +++++++++++++++---- src/screens/deck-form/card-form-wrapper.tsx | 11 ++-- src/screens/deck-form/card-preview.tsx | 11 ++-- src/screens/deck-form/deck-form-screen.tsx | 7 +-- src/screens/deck-form/formatting-switcher.tsx | 39 ++++++++++++ ...-store.ts => card-form-store-interface.ts} | 9 ++- .../deck-form/store/deck-form-store.ts | 4 +- .../store/quick-add-card-form-store.ts | 4 +- .../deck-review/store/card-preview-store.ts | 20 +++--- .../deck-review/store/review-store.test.ts | 20 +++++- src/screens/deck-review/store/review-store.ts | 2 +- .../store/user-settings-store.tsx | 2 +- src/store/deck-list-store.test.ts | 12 ++++ src/store/user-store.ts | 10 +++ src/translations/t.ts | 4 ++ src/ui/label.tsx | 14 ++++- src/ui/wysiwyg-field/wysiwig-field.tsx | 7 +++ src/ui/wysiwyg-field/wysiwyg-field.css | 2 +- 24 files changed, 244 insertions(+), 55 deletions(-) create mode 100644 src/lib/telegram/cloud-storage.ts rename src/lib/telegram/{hapticNotification.ts => haptics.ts} (100%) create mode 100644 src/lib/telegram/storage-adapter.ts create mode 100644 src/screens/deck-form/formatting-switcher.tsx rename src/screens/deck-form/store/{card-form-store.ts => card-form-store-interface.ts} (51%) diff --git a/src/lib/cache/cache-promise.test.ts b/src/lib/cache/cache-promise.test.ts index 8b575339..9bfad550 100644 --- a/src/lib/cache/cache-promise.test.ts +++ b/src/lib/cache/cache-promise.test.ts @@ -1,4 +1,4 @@ -import { test, vi, expect } from "vitest"; +import { expect, test, vi } from "vitest"; import { cachePromise } from "./cache-promise.ts"; test("should cache the resolved value of a promise", async () => { diff --git a/src/lib/mobx-form/persistable-field.ts b/src/lib/mobx-form/persistable-field.ts index aa510d05..52e70aa9 100644 --- a/src/lib/mobx-form/persistable-field.ts +++ b/src/lib/mobx-form/persistable-field.ts @@ -1,5 +1,6 @@ import { makePersistable } from "mobx-persist-store"; import { FieldWithValue } from "./field-with-value.ts"; +import { storageAdapter } from "../telegram/storage-adapter.ts"; export const persistableField = >( field: T, @@ -9,7 +10,7 @@ export const persistableField = >( makePersistable(field, { name: storageKey, properties: ["value"], - storage: window.localStorage, + storage: storageAdapter, expireIn: expireIn, }); diff --git a/src/lib/sanitize-html/remove-all-tags.ts b/src/lib/sanitize-html/remove-all-tags.ts index 1f04e770..22121842 100644 --- a/src/lib/sanitize-html/remove-all-tags.ts +++ b/src/lib/sanitize-html/remove-all-tags.ts @@ -1,5 +1,8 @@ import sanitizeHtml from "sanitize-html"; export const removeAllTags = (text: string) => { - return sanitizeHtml(text); + return sanitizeHtml(text, { + allowedTags: [], + allowedAttributes: {}, + }); }; diff --git a/src/lib/telegram/cloud-storage.ts b/src/lib/telegram/cloud-storage.ts new file mode 100644 index 00000000..cc41e094 --- /dev/null +++ b/src/lib/telegram/cloud-storage.ts @@ -0,0 +1,42 @@ +import WebApp from "@twa-dev/sdk"; +import { type StorageController } from "mobx-persist-store"; + +// An adapter of the Telegram cloud storage to the mobx-persist-store interface +export const cloudStorageAdapter: StorageController = { + getItem(key: string) { + return new Promise((resolve, reject) => { + WebApp.CloudStorage.getItem(key, (err, value) => { + if (err != null) { + return reject(err); + } else { + // @ts-ignore + return resolve(value); + } + }); + }); + }, + removeItem(key: string) { + return new Promise((resolve, reject) => { + WebApp.CloudStorage.removeItem(key, (err, result) => { + if (err != null) { + return reject(err); + } else { + // @ts-ignore + return resolve(result); + } + }); + }); + }, + setItem(key: string, value: any) { + return new Promise((resolve, reject) => { + WebApp.CloudStorage.setItem(key, value, (err, result) => { + if (err != null) { + return reject(err); + } else { + // @ts-ignore + return resolve(result); + } + }); + }); + }, +}; diff --git a/src/lib/telegram/hapticNotification.ts b/src/lib/telegram/haptics.ts similarity index 100% rename from src/lib/telegram/hapticNotification.ts rename to src/lib/telegram/haptics.ts diff --git a/src/lib/telegram/storage-adapter.ts b/src/lib/telegram/storage-adapter.ts new file mode 100644 index 00000000..9aeeea59 --- /dev/null +++ b/src/lib/telegram/storage-adapter.ts @@ -0,0 +1,6 @@ +import WebApp from "@twa-dev/sdk"; +import { cloudStorageAdapter } from "./cloud-storage.ts"; + +export const storageAdapter = WebApp.isVersionAtLeast("6.9") + ? cloudStorageAdapter + : window.localStorage; diff --git a/src/screens/deck-form/card-form-view.tsx b/src/screens/deck-form/card-form-view.tsx index b7d6da71..5b09da98 100644 --- a/src/screens/deck-form/card-form-view.tsx +++ b/src/screens/deck-form/card-form-view.tsx @@ -1,5 +1,5 @@ import { observer, useLocalObservable } from "mobx-react-lite"; -import { CardFormStore } from "./store/card-form-store.ts"; +import { CardFormStoreInterface } from "./store/card-form-store-interface.ts"; import { assert } from "../../lib/typescript/assert.ts"; import { useMainButton } from "../../lib/telegram/use-main-button.tsx"; import { t } from "../../translations/t.ts"; @@ -24,9 +24,12 @@ import React from "react"; import { ValidationError } from "../../ui/validation-error.tsx"; import { showAlert } from "../../lib/telegram/show-alert.ts"; import { WysiwygField } from "../../ui/wysiwyg-field/wysiwig-field.tsx"; +import { userStore } from "../../store/user-store.ts"; +import { Input } from "../../ui/input.tsx"; +import { FormattingSwitcher } from "./formatting-switcher.tsx"; type Props = { - cardFormStore: CardFormStore; + cardFormStore: CardFormStoreInterface; }; export const CardFormView = observer((props: Props) => { @@ -54,17 +57,45 @@ export const CardFormView = observer((props: Props) => { ), })); + const isCardFormattingOn = userStore.isCardFormattingOn.value; + return ( - +
+ - + +
{t("card_advanced")} @@ -160,8 +191,16 @@ export const CardFormView = observer((props: Props) => { )} -