Skip to content

Commit

Permalink
Card preview (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
kubk authored Jan 9, 2024
1 parent c2465fa commit 43cbcdf
Show file tree
Hide file tree
Showing 16 changed files with 169 additions and 28 deletions.
4 changes: 2 additions & 2 deletions src/screens/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ReviewStoreProvider } from "./deck-review/store/review-store-context.ts
import { screenStore } from "../store/screen-store.ts";
import { DeckFormScreen } from "./deck-form/deck-form-screen.tsx";
import { DeckFormStoreProvider } from "./deck-form/store/deck-form-store-context.tsx";
import { QuickAddCardForm } from "./deck-form/quick-add-card-form.tsx";
import { QuickAddCardFormPage } from "./deck-form/quick-add-card-form-page.tsx";
import { VersionWarning } from "./shared/version-warning.tsx";
import React from "react";
import { UserSettingsStoreProvider } from "./user-settings/store/user-settings-store-context.tsx";
Expand Down Expand Up @@ -90,7 +90,7 @@ export const App = observer(() => {
)}
{screenStore.screen.type === "cardQuickAddForm" && (
<PreventTelegramSwipeDownClosingIos>
<QuickAddCardForm />
<QuickAddCardFormPage />
</PreventTelegramSwipeDownClosingIos>
)}
{screenStore.screen.type === "userSettings" && (
Expand Down
11 changes: 10 additions & 1 deletion src/screens/deck-form/card-form-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ import { CardFormType } from "./store/deck-form-store.ts";
import { HintTransparent } from "../../ui/hint-transparent.tsx";
import { t } from "../../translations/t.ts";
import { Screen } from "../shared/screen.tsx";
import { CenteredUnstyledButton } from "../../ui/centered-unstyled-button.tsx";
import { isFormValid } from "../../lib/mobx-form/form-has-error.ts";

type Props = {
cardForm: CardFormType;
onPreviewClick: () => void;
};

export const CardFormView = observer((props: Props) => {
const { cardForm } = props;
const { cardForm, onPreviewClick } = props;

return (
<Screen title={cardForm ? t("edit_card") : t("add_card")}>
Expand All @@ -30,6 +33,12 @@ export const CardFormView = observer((props: Props) => {
<Input field={cardForm.example} rows={2} type={"textarea"} />
<HintTransparent>{t("card_field_example_hint")}</HintTransparent>
</Label>

{isFormValid(cardForm) && (
<CenteredUnstyledButton onClick={onPreviewClick}>
{t("card_preview")}
</CenteredUnstyledButton>
)}
</Screen>
);
});
9 changes: 8 additions & 1 deletion src/screens/deck-form/card-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,12 @@ export const CardForm = observer(() => {
deckFormStore.onCardBack();
});

return <CardFormView cardForm={cardForm} />;
return (
<CardFormView
cardForm={cardForm}
onPreviewClick={() => {
deckFormStore.isCardPreviewSelected.setTrue();
}}
/>
);
});
40 changes: 40 additions & 0 deletions src/screens/deck-form/card-preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { observer } from "mobx-react-lite";
import { Screen } from "../shared/screen.tsx";
import { useBackButton } from "../../lib/telegram/use-back-button.tsx";
import { Card } from "../deck-review/card.tsx";
import { css } from "@emotion/css";
import { t } from "../../translations/t.ts";
import { CardFormType } from "./store/deck-form-store.ts";

type Props = {
form: CardFormType;
onBack: () => void;
};

export const CardPreview = observer((props: Props) => {
const { form, onBack } = props;

useBackButton(() => {
onBack();
});

return (
<Screen title={t("card_preview")}>
<div className={css({ position: "relative", marginTop: 40 })}>
<Card
card={{
isOpened: true,
back: form.back.value,
front: form.front.value,
example: form.example.value,
speak: () => {},
deckSpeakField: "front",
isSpeakingCardsEnabledSettings: false,
}}
animate={{}}
style={{}}
/>
</div>
</Screen>
);
});
13 changes: 13 additions & 0 deletions src/screens/deck-form/deck-form-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,29 @@ import { DeckForm } from "./deck-form.tsx";
import { CardForm } from "./card-form.tsx";
import { useDeckFormStore } from "./store/deck-form-store-context.tsx";
import { CardList } from "./card-list.tsx";
import { CardPreview } from "./card-preview.tsx";
import { assert } from "../../lib/typescript/assert.ts";

export const DeckFormScreen = observer(() => {
const deckFormStore = useDeckFormStore();

if (deckFormStore.deckFormScreen === "cardList") {
return <CardList />;
}

if (deckFormStore.deckFormScreen === "cardForm") {
return <CardForm />;
}

if (deckFormStore.deckFormScreen === "cardPreview") {
assert(deckFormStore.cardForm, "Card should not be empty before preview");
return (
<CardPreview
form={deckFormStore.cardForm}
onBack={deckFormStore.isCardPreviewSelected.setFalse}
/>
);
}

return <DeckForm />;
});
15 changes: 3 additions & 12 deletions src/screens/deck-form/deck-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { t } from "../../translations/t.ts";
import { deckListStore } from "../../store/deck-list-store.ts";
import { reset } from "../../ui/reset.ts";
import { Screen } from "../shared/screen.tsx";
import { CenteredUnstyledButton } from "../../ui/centered-unstyled-button.tsx";

export const DeckForm = observer(() => {
const deckFormStore = useDeckFormStore();
Expand Down Expand Up @@ -165,25 +166,15 @@ export const DeckForm = observer(() => {
{t("add_card")}
</Button>
{deckFormStore.form.id ? (
<button
className={cx(
reset.button,
css({
width: "100%",
color: theme.linkColor,
fontSize: 14,
paddingTop: 6,
textTransform: "uppercase",
}),
)}
<CenteredUnstyledButton
onClick={() => {
assert(deckFormStore.form);
assert(deckFormStore.form.id);
deckListStore.goDeckById(deckFormStore.form.id, "main");
}}
>
{t("deck_preview")}
</button>
</CenteredUnstyledButton>
) : null}
</Screen>
);
Expand Down
20 changes: 20 additions & 0 deletions src/screens/deck-form/quick-add-card-form-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { observer } from "mobx-react-lite";
import React, { useState } from "react";
import { QuickAddCardFormStore } from "./store/quick-add-card-form-store.ts";
import { CardPreview } from "./card-preview.tsx";
import { QuickAddForm } from "./quick-add-form.tsx";

export const QuickAddCardFormPage = observer(() => {
const [quickAddCardStore] = useState(() => new QuickAddCardFormStore());

if (quickAddCardStore.isCardPreviewSelected.value) {
return (
<CardPreview
form={quickAddCardStore.form}
onBack={quickAddCardStore.isCardPreviewSelected.setFalse}
/>
);
}

return <QuickAddForm quickAddCardStore={quickAddCardStore} />;
});
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { observer } from "mobx-react-lite";
import React, { useState } from "react";
import { CardFormView } from "./card-form-view.tsx";
import { QuickAddCardFormStore } from "./store/quick-add-card-form-store.ts";
import { useMainButton } from "../../lib/telegram/use-main-button.tsx";
import { t } from "../../translations/t.ts";
import { useBackButton } from "../../lib/telegram/use-back-button.tsx";
import { QuickAddCardFormStore } from "./store/quick-add-card-form-store.ts";
import { useTelegramProgress } from "../../lib/telegram/use-telegram-progress.tsx";
import { t } from "../../translations/t.ts";
import { CardFormView } from "./card-form-view.tsx";
import React from "react";

export const QuickAddCardForm = observer(() => {
const [quickAddCardStore] = useState(() => new QuickAddCardFormStore());
type Props = { quickAddCardStore: QuickAddCardFormStore };

export const QuickAddForm = observer((props: Props) => {
const { quickAddCardStore } = props;
useMainButton(t("save"), () => {
quickAddCardStore.onSave();
});
Expand All @@ -18,5 +19,10 @@ export const QuickAddCardForm = observer(() => {
});
useTelegramProgress(() => quickAddCardStore.isSending);

return <CardFormView cardForm={quickAddCardStore.form} />;
return (
<CardFormView
cardForm={quickAddCardStore.form}
onPreviewClick={quickAddCardStore.isCardPreviewSelected.setTrue}
/>
);
});
5 changes: 5 additions & 0 deletions src/screens/deck-form/store/deck-form-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
} from "../../../../functions/db/deck/decks-with-cards-schema.ts";
import { SpeakLanguageEnum } from "../../../lib/voice-playback/speak.ts";
import { t } from "../../../translations/t.ts";
import { BooleanToggle } from "../../../lib/mobx-form/boolean-toggle.ts";

export type CardFormType = {
front: TextField<string>;
Expand Down Expand Up @@ -79,6 +80,7 @@ export type CardFilterDirection = "desc" | "asc";
export class DeckFormStore {
cardFormIndex?: number;
cardFormType?: "new" | "edit";
isCardPreviewSelected = new BooleanToggle(false);
form?: DeckFormType;
isSending = false;
isCardList = false;
Expand All @@ -94,6 +96,9 @@ export class DeckFormStore {

get deckFormScreen() {
if (this.cardFormIndex !== undefined) {
if (this.isCardPreviewSelected.value) {
return "cardPreview";
}
return "cardForm";
}
if (this.isCardList) {
Expand Down
2 changes: 2 additions & 0 deletions src/screens/deck-form/store/quick-add-card-form-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { TextField } from "../../../lib/mobx-form/text-field.ts";
import { AddCardRequest } from "../../../../functions/add-card.ts";
import { deckListStore } from "../../../store/deck-list-store.ts";
import { t } from "../../../translations/t.ts";
import { BooleanToggle } from "../../../lib/mobx-form/boolean-toggle.ts";

export class QuickAddCardFormStore {
form: CardFormType = {
Expand All @@ -21,6 +22,7 @@ export class QuickAddCardFormStore {
example: new TextField(""),
};
isSending = false;
isCardPreviewSelected = new BooleanToggle(false);

constructor() {
makeAutoObservable(this, {}, { autoBind: true });
Expand Down
4 changes: 2 additions & 2 deletions src/screens/deck-review/card-field-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ export const CardFieldView = (props: { text: string }) => {
return (
<span
dangerouslySetInnerHTML={{
__html: sanitize(text)
__html: sanitize(text),
}}
></span>
/>
);
};
4 changes: 2 additions & 2 deletions src/screens/deck-review/card-speaker.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { CardUnderReviewStore } from "./store/card-under-review-store.ts";
import { isSpeechSynthesisSupported } from "../../lib/voice-playback/speak.ts";
import { throttle } from "../../lib/throttle/throttle.ts";
import { css, cx } from "@emotion/css";
import { theme } from "../../ui/theme.tsx";
import React from "react";
import { observer } from "mobx-react-lite";
import { LimitedCardUnderReviewStore } from "./card.tsx";

type Props = {
card: CardUnderReviewStore;
card: LimitedCardUnderReviewStore;
type: "front" | "back";
};

Expand Down
13 changes: 12 additions & 1 deletion src/screens/deck-review/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,19 @@ export const cardSize = 310;

type FramerMotionProps = Pick<MotionProps, "style" | "animate" | "initial">;

export type LimitedCardUnderReviewStore = Pick<
CardUnderReviewStore,
| "isOpened"
| "deckSpeakField"
| "isSpeakingCardsEnabledSettings"
| "speak"
| "front"
| "back"
| "example"
>;

type Props = {
card: CardUnderReviewStore;
card: LimitedCardUnderReviewStore;
} & FramerMotionProps;

export const Card = observer(({ card, style, animate }: Props) => {
Expand Down
2 changes: 2 additions & 0 deletions src/store/screen-store.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { makeAutoObservable } from "mobx";
import { CardFormType } from "../screens/deck-form/store/deck-form-store.ts";

type Route =
| { type: "main" }
| { type: "deckMine"; deckId: number; backScreen?: RouteType }
| { type: "deckPublic"; deckId: number; backScreen?: RouteType }
| { type: "deckForm"; deckId?: number; folder?: { id: number; name: string } }
| { type: "cardPreview"; form: CardFormType }
| { type: "folderForm"; folderId?: number }
| { type: "folderPreview"; folderId: number }
| { type: "deckOrFolderChoose" }
Expand Down
4 changes: 4 additions & 0 deletions src/translations/t.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const en = {
add_card: "Add card",
edit_card: "Edit card",
deck_preview: "Deck preview",
card_preview: "Card preview",
add_card_short: "Add card",
add_deck_short: "Deck",
card_front_title: "Front side",
Expand Down Expand Up @@ -130,6 +131,7 @@ type Translation = typeof en;

const ru: Translation = {
choose_what_to_create: "Выберите что создать",
card_preview: "Предпросмотр карточки",
deck: "Колода",
add_deck_short: "Колода",
deck_description: "Коллекция карточек",
Expand Down Expand Up @@ -253,6 +255,7 @@ const ru: Translation = {
};

const es: Translation = {
card_preview: "Vista previa de la tarjeta",
review_folder: "Repasar carpeta",
folder_description: "Una colección de mazos",
add_deck_short: "Mazo",
Expand Down Expand Up @@ -381,6 +384,7 @@ const es: Translation = {
};

const ptBr: Translation = {
card_preview: "Visualização do cartão",
review_folder: "Revisar pasta",
add_deck_short: "Baralho",
choose_what_to_create: "Escolha o que criar",
Expand Down
31 changes: 31 additions & 0 deletions src/ui/centered-unstyled-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { css, cx } from "@emotion/css";
import { reset } from "./reset.ts";
import { theme } from "./theme.tsx";
import React, { ReactNode } from "react";

type Props = {
children: ReactNode;
onClick: () => void;
};

export const CenteredUnstyledButton = (props: Props) => {
const { children, onClick } = props;

return (
<button
className={cx(
reset.button,
css({
width: "100%",
color: theme.linkColor,
fontSize: 14,
paddingTop: 6,
textTransform: "uppercase",
}),
)}
onClick={onClick}
>
{children}
</button>
);
};

0 comments on commit 43cbcdf

Please sign in to comment.