-
+
-
+
{t("card_advanced")}
diff --git a/src/screens/deck-form/card-list.tsx b/src/screens/deck-form/card-list.tsx
index 479d9980..b4f6234d 100644
--- a/src/screens/deck-form/card-list.tsx
+++ b/src/screens/deck-form/card-list.tsx
@@ -13,6 +13,7 @@ import { t } from "../../translations/t.ts";
import { Screen } from "../shared/screen.tsx";
import { removeAllTags } from "../../lib/sanitize-html/remove-all-tags.ts";
import { tapScale } from "../../lib/animations/tap-scale.ts";
+import { Flex } from "../../ui/flex.tsx";
export const CardList = observer(() => {
const deckFormStore = useDeckFormStore();
@@ -35,13 +36,7 @@ export const CardList = observer(() => {
field={deckFormStore.cardFilter.text}
placeholder={t("search_card")}
/>
-
+
{t("sort_by")}
{[
{
@@ -80,7 +75,7 @@ export const CardList = observer(() => {
);
})}
-
+
>
)}
{deckFormStore.filteredCards.map((cardForm, i) => (
diff --git a/src/screens/deck-form/deck-form.tsx b/src/screens/deck-form/deck-form.tsx
index 9f994627..67b07e16 100644
--- a/src/screens/deck-form/deck-form.tsx
+++ b/src/screens/deck-form/deck-form.tsx
@@ -27,6 +27,7 @@ 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";
+import { Flex } from "../../ui/flex.tsx";
export const DeckForm = observer(() => {
const deckFormStore = useDeckFormStore();
@@ -110,14 +111,7 @@ export const DeckForm = observer(() => {
/>
{deckFormStore.isSpeakingCardEnabled ? (
-
+
{t("voice_language")}
@@ -149,7 +143,7 @@ export const DeckForm = observer(() => {
/>
) : null}
-
+
) : (
<>
{t("card_speak_description")}
diff --git a/src/screens/deck-list/main-screen.tsx b/src/screens/deck-list/main-screen.tsx
index 4a7fe068..c2bfae68 100644
--- a/src/screens/deck-list/main-screen.tsx
+++ b/src/screens/deck-list/main-screen.tsx
@@ -18,6 +18,7 @@ import { ViewMoreDecksToggle } from "./view-more-decks-toggle.tsx";
import { t } from "../../translations/t.ts";
import { links } from "../shared/links.ts";
import { tapScale } from "../../lib/animations/tap-scale.ts";
+import { Flex } from "../../ui/flex.tsx";
export const MainScreen = observer(() => {
useMount(() => {
@@ -25,14 +26,7 @@ export const MainScreen = observer(() => {
});
return (
-
+
{
) : undefined
}
/>
-
+
{deckListStore.isMyInfoLoading &&
range(deckListStore.skeletonLoaderData.myDecksCount).map((i) => (
@@ -131,18 +119,12 @@ export const MainScreen = observer(() => {
{deckListStore.areAllDecksReviewed && (
{t("all_decks_reviewed")}
)}
-
+
-
+
{deckListStore.myInfo ? (
<>
{deckListStore.publicDecks.map((deck) => (
@@ -175,7 +157,7 @@ export const MainScreen = observer(() => {
range(deckListStore.skeletonLoaderData.publicCount).map((i) => (
))}
-
+
{deckListStore.myInfo && (
@@ -215,6 +197,6 @@ export const MainScreen = observer(() => {
>
)}
-
+
);
});
diff --git a/src/screens/deck-or-folder-choose/choice.tsx b/src/screens/deck-or-folder-choose/choice.tsx
index 64f32402..36891e53 100644
--- a/src/screens/deck-or-folder-choose/choice.tsx
+++ b/src/screens/deck-or-folder-choose/choice.tsx
@@ -1,5 +1,6 @@
import { css, cx } from "@emotion/css";
import { theme } from "../../ui/theme.tsx";
+import { Flex } from "../../ui/flex.tsx";
type Props = {
icon: string;
@@ -26,17 +27,10 @@ export const Choice = (props: Props) => {
cursor: "pointer",
})}
>
-
+
{title}
-
+
{description}
);
diff --git a/src/screens/deck-or-folder-choose/deck-or-folder-choose.tsx b/src/screens/deck-or-folder-choose/deck-or-folder-choose.tsx
index 9e5df3c2..e95ce749 100644
--- a/src/screens/deck-or-folder-choose/deck-or-folder-choose.tsx
+++ b/src/screens/deck-or-folder-choose/deck-or-folder-choose.tsx
@@ -1,9 +1,9 @@
import { observer } from "mobx-react-lite";
-import { css } from "@emotion/css";
import { Choice } from "./choice.tsx";
import { screenStore } from "../../store/screen-store.ts";
import { useBackButton } from "../../lib/telegram/use-back-button.tsx";
import { t } from "../../translations/t.ts";
+import { Flex } from "../../ui/flex.tsx";
export const DeckOrFolderChoose = observer(() => {
useBackButton(() => {
@@ -11,24 +11,15 @@ export const DeckOrFolderChoose = observer(() => {
});
return (
-
{t("choose_what_to_create")}
-
+
{
screenStore.go({ type: "folderForm" });
}}
/>
-
-
+
+
);
});
diff --git a/src/screens/deck-review/deck-finished.tsx b/src/screens/deck-review/deck-finished.tsx
index 62d1707f..7f56caff 100644
--- a/src/screens/deck-review/deck-finished.tsx
+++ b/src/screens/deck-review/deck-finished.tsx
@@ -1,7 +1,6 @@
import React from "react";
import { observer } from "mobx-react-lite";
import { DeckFinishedModal } from "./deck-finished-modal.tsx";
-import { css } from "@emotion/css";
import { useReviewStore } from "./store/review-store-context.tsx";
import { useMount } from "../../lib/react/use-mount.ts";
import { screenStore } from "../../store/screen-store.ts";
@@ -11,6 +10,7 @@ import { t } from "../../translations/t.ts";
import { getEncouragingMessage } from "../../translations/get-encouraging-message.tsx";
import { WantMoreCardsButton } from "./want-more-cards-button.tsx";
import { deckListStore } from "../../store/deck-list-store.ts";
+import { Flex } from "../../ui/flex.tsx";
type Props = {
type: "deck" | "repeat_all";
@@ -33,13 +33,7 @@ export const DeckFinished = observer((props: Props) => {
return (
-
+
{type === "deck" ? t("review_deck_finished") : t("review_all_cards")}
@@ -50,7 +44,7 @@ export const DeckFinished = observer((props: Props) => {
) : (
{getEncouragingMessage()} 😊
)}
-
+
);
});
diff --git a/src/screens/deck-review/deck-preview.tsx b/src/screens/deck-review/deck-preview.tsx
index fe535f1d..a855a40c 100644
--- a/src/screens/deck-review/deck-preview.tsx
+++ b/src/screens/deck-review/deck-preview.tsx
@@ -18,6 +18,7 @@ import { DeckFolderDescription } from "../shared/deck-folder-description.tsx";
import { useScrollToTopOnMount } from "../../lib/react/use-scroll-to-top-mount.ts";
import { userStore } from "../../store/user-store.ts";
import { redirectUserToDeckOrFolderLink } from "../share-deck/redirect-user-to-deck-or-folder-link.tsx";
+import { Flex } from "../../ui/flex.tsx";
export const DeckPreview = observer(() => {
const reviewStore = useReviewStore();
@@ -50,15 +51,7 @@ export const DeckPreview = observer(() => {
}
return (
-
+
{
paddingTop: 8,
})}
>
-
+
{t("cards_to_repeat")}:
{
@@ -110,8 +103,8 @@ export const DeckPreview = observer(() => {
.length
}
-
-
+
+
{t("cards_new")}:
{
@@ -119,11 +112,11 @@ export const DeckPreview = observer(() => {
.length
}
-
-
+
+
{t("cards_total")}:
{deck.deck_card.length}
-
+
)}
@@ -214,6 +207,6 @@ export const DeckPreview = observer(() => {
>
)}
-
+
);
});
diff --git a/src/screens/deck-review/repeat-all-screen.tsx b/src/screens/deck-review/repeat-all-screen.tsx
index 7b25cabe..99bcc9b2 100644
--- a/src/screens/deck-review/repeat-all-screen.tsx
+++ b/src/screens/deck-review/repeat-all-screen.tsx
@@ -8,7 +8,7 @@ import React from "react";
import { Hint } from "../../ui/hint.tsx";
import { t } from "../../translations/t.ts";
import { WantMoreCardsButton } from "./want-more-cards-button.tsx";
-import { css } from "@emotion/css";
+import { Flex } from "../../ui/flex.tsx";
export const RepeatAllScreen = observer(() => {
const reviewStore = useReviewStore();
@@ -29,13 +29,13 @@ export const RepeatAllScreen = observer(() => {
}
return (
-
+
{t("no_cards_to_review_all")}
{deckListStore.newCardsCount > 0 ? (
) : null}
-
+
);
});
diff --git a/src/screens/deck-review/store/review-store.test.ts b/src/screens/deck-review/store/review-store.test.ts
index 86642b4e..aa9f40e0 100644
--- a/src/screens/deck-review/store/review-store.test.ts
+++ b/src/screens/deck-review/store/review-store.test.ts
@@ -207,93 +207,95 @@ describe("card form store", () => {
reviewCardsReviewMock.mockResolvedValueOnce(() => Promise.resolve());
expect(reviewCardsReviewMock).toHaveBeenCalledTimes(0);
const reviewStore = new ReviewStore();
- reviewStore.startDeckReview(createDeckWithCards([
- {
- id: 3,
- deck_id: 1,
- created_at: "2023-10-06T02:13:20.985Z",
- example: null,
- front: "time",
- back: "Время",
- type: "repeat",
- answer_type: "remember",
- answers: null,
- options: null,
- },
- {
- id: 4,
- deck_id: 1,
- created_at: "2023-10-06T02:13:20.985Z",
- example: null,
- front: "year",
- back: "Год",
- type: "repeat",
- answer_type: "remember",
- answers: null,
- options: null,
- },
- {
- id: 5,
- deck_id: 1,
- created_at: "2023-10-06T02:13:20.985Z",
- example: null,
- front: "way",
- back: "Дорога",
- type: "repeat",
- answer_type: "remember",
- answers: null,
- options: null,
- },
- {
- id: 6,
- deck_id: 1,
- created_at: "2023-10-06T02:13:20.985Z",
- example: null,
- front: "card 4",
- back: "card 4",
- type: "repeat",
- answer_type: "remember",
- answers: null,
- options: null,
- },
-
- {
- id: 7,
- deck_id: 1,
- created_at: "2023-10-06T02:13:20.985Z",
- example: null,
- front: "card 7",
- back: "card 7",
- type: "repeat",
- answer_type: "remember",
- answers: null,
- options: null,
- },
- {
- id: 8,
- deck_id: 1,
- created_at: "2023-10-06T02:13:20.985Z",
- example: null,
- front: "card 8",
- back: "card 8",
- type: "repeat",
- answer_type: "remember",
- answers: null,
- options: null,
- },
- {
- id: 9,
- deck_id: 1,
- created_at: "2023-10-06T02:13:20.985Z",
- example: null,
- front: "card 9",
- back: "card 9",
- type: "repeat",
- answer_type: "remember",
- answers: null,
- options: null,
- },
- ]));
+ reviewStore.startDeckReview(
+ createDeckWithCards([
+ {
+ id: 3,
+ deck_id: 1,
+ created_at: "2023-10-06T02:13:20.985Z",
+ example: null,
+ front: "time",
+ back: "Время",
+ type: "repeat",
+ answer_type: "remember",
+ answers: null,
+ options: null,
+ },
+ {
+ id: 4,
+ deck_id: 1,
+ created_at: "2023-10-06T02:13:20.985Z",
+ example: null,
+ front: "year",
+ back: "Год",
+ type: "repeat",
+ answer_type: "remember",
+ answers: null,
+ options: null,
+ },
+ {
+ id: 5,
+ deck_id: 1,
+ created_at: "2023-10-06T02:13:20.985Z",
+ example: null,
+ front: "way",
+ back: "Дорога",
+ type: "repeat",
+ answer_type: "remember",
+ answers: null,
+ options: null,
+ },
+ {
+ id: 6,
+ deck_id: 1,
+ created_at: "2023-10-06T02:13:20.985Z",
+ example: null,
+ front: "card 4",
+ back: "card 4",
+ type: "repeat",
+ answer_type: "remember",
+ answers: null,
+ options: null,
+ },
+
+ {
+ id: 7,
+ deck_id: 1,
+ created_at: "2023-10-06T02:13:20.985Z",
+ example: null,
+ front: "card 7",
+ back: "card 7",
+ type: "repeat",
+ answer_type: "remember",
+ answers: null,
+ options: null,
+ },
+ {
+ id: 8,
+ deck_id: 1,
+ created_at: "2023-10-06T02:13:20.985Z",
+ example: null,
+ front: "card 8",
+ back: "card 8",
+ type: "repeat",
+ answer_type: "remember",
+ answers: null,
+ options: null,
+ },
+ {
+ id: 9,
+ deck_id: 1,
+ created_at: "2023-10-06T02:13:20.985Z",
+ example: null,
+ front: "card 9",
+ back: "card 9",
+ type: "repeat",
+ answer_type: "remember",
+ answers: null,
+ options: null,
+ },
+ ]),
+ );
expect(reviewStore.isFinished).toBeFalsy();
reviewStore.open();
diff --git a/src/screens/folder-review/folder-preview.tsx b/src/screens/folder-review/folder-preview.tsx
index 1f7d1f19..e21e5d0e 100644
--- a/src/screens/folder-review/folder-preview.tsx
+++ b/src/screens/folder-review/folder-preview.tsx
@@ -20,6 +20,7 @@ import { DeckFolderDescription } from "../shared/deck-folder-description.tsx";
import { useScrollToTopOnMount } from "../../lib/react/use-scroll-to-top-mount.ts";
import { redirectUserToDeckOrFolderLink } from "../share-deck/redirect-user-to-deck-or-folder-link.tsx";
import { userStore } from "../../store/user-store.ts";
+import { Flex } from "../../ui/flex.tsx";
export const FolderPreview = observer(() => {
const reviewStore = useReviewStore();
@@ -47,14 +48,7 @@ export const FolderPreview = observer(() => {
}
return (
-
+
{
paddingTop: 8,
})}
>
-
+
{t("cards_to_repeat")}:
{
@@ -106,8 +100,8 @@ export const FolderPreview = observer(() => {
.length
}
-
-
+
+
{t("cards_new")}:
{
@@ -115,8 +109,8 @@ export const FolderPreview = observer(() => {
.length
}
-
-
+
+
{t("cards_total")}:
{folder.decks.reduce(
@@ -124,7 +118,7 @@ export const FolderPreview = observer(() => {
0,
)}
-
+
)}
@@ -201,14 +195,7 @@ export const FolderPreview = observer(() => {
-
+
{folder.decks.map((deck, i) => {
return (
@@ -224,7 +211,7 @@ export const FolderPreview = observer(() => {
{folder.cardsToReview.length === 0 && (
{t("no_cards_to_review_in_deck")}
)}
-
-
+
+
);
});
diff --git a/src/screens/shared/deck-row-with-cards-to-review/deck-row-with-cards-to-review.tsx b/src/screens/shared/deck-row-with-cards-to-review/deck-row-with-cards-to-review.tsx
index a9408861..ebe6ec5b 100644
--- a/src/screens/shared/deck-row-with-cards-to-review/deck-row-with-cards-to-review.tsx
+++ b/src/screens/shared/deck-row-with-cards-to-review/deck-row-with-cards-to-review.tsx
@@ -5,6 +5,7 @@ import React from "react";
import { DeckCardDbTypeWithType } from "../../../store/deck-list-store.ts";
import { CardsToReviewCount } from "./cards-to-review-count.tsx";
import { tapScale } from "../../../lib/animations/tap-scale.ts";
+import { Flex } from "../../../ui/flex.tsx";
type Props = {
item: {
@@ -42,13 +43,7 @@ export const DeckRowWithCardsToReview = observer((props: Props) => {
>
{item.name}
-
+
card.type === "repeat")}
color={theme.orange}
@@ -57,7 +52,7 @@ export const DeckRowWithCardsToReview = observer((props: Props) => {
items={item.cardsToReview.filter((card) => card.type === "new")}
color={theme.success}
/>
-
+
);
});
diff --git a/src/screens/user-statistics/user-statistics-screen.tsx b/src/screens/user-statistics/user-statistics-screen.tsx
index 71f02383..46cd1900 100644
--- a/src/screens/user-statistics/user-statistics-screen.tsx
+++ b/src/screens/user-statistics/user-statistics-screen.tsx
@@ -17,6 +17,7 @@ import {
import { LegendItem } from "./legend-item.tsx";
import { DeckLoading } from "../shared/deck-loading.tsx";
import { EmptyStudyFrequencyChartText } from "./empty-study-frequency-chart-text.tsx";
+import { Flex } from "../../ui/flex.tsx";
const pieChartWidth = 250;
const pieChartHeight = 200;
@@ -115,39 +116,21 @@ export const UserStatisticsScreen = observer(() => {
{!userStatisticsStore.isFrequencyChartEmpty && (
<>
-
-
+
+
{t("user_stats_chart_min_expl")}
-
-
+
+
+
{t("user_stats_chart_max_expl")}
-
-
+
+
{t("user_stats_learning_time_hint")}
diff --git a/src/ui/flex.tsx b/src/ui/flex.tsx
new file mode 100644
index 00000000..ad0c5592
--- /dev/null
+++ b/src/ui/flex.tsx
@@ -0,0 +1,50 @@
+import { CSSProperties, ReactNode } from "react";
+import { css, cx } from "@emotion/css";
+
+type Props = {
+ children: ReactNode;
+ direction?: CSSProperties["flexDirection"];
+ justifyContent?: CSSProperties["justifyContent"];
+ alignItems?: CSSProperties["alignItems"];
+ alignSelf?: CSSProperties["alignSelf"];
+ gap?: CSSProperties["gap"];
+ ml?: CSSProperties["marginLeft"];
+ mr?: CSSProperties["marginRight"];
+ mt?: CSSProperties["marginTop"];
+ mb?: CSSProperties["marginBottom"];
+ pt?: CSSProperties["paddingTop"];
+ pb?: CSSProperties["paddingBottom"];
+ pl?: CSSProperties["paddingLeft"];
+ pr?: CSSProperties["paddingRight"];
+ className?: string;
+};
+
+export const Flex = (props: Props) => {
+ const { children, className } = props;
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/src/ui/input.tsx b/src/ui/input.tsx
index d4993f0d..ad769e57 100644
--- a/src/ui/input.tsx
+++ b/src/ui/input.tsx
@@ -1,10 +1,11 @@
-import { ChangeEvent, useEffect, useRef } from "react";
+import React, { ChangeEvent, useEffect, useRef } from "react";
import { css } from "@emotion/css";
import { theme } from "./theme.tsx";
import { TextField } from "mobx-form-lite";
import { observer } from "mobx-react-lite";
import autosize from "autosize";
import { ValidationError } from "./validation-error.tsx";
+import { Flex } from "./flex.tsx";
interface Props {
placeholder?: string;
@@ -33,7 +34,7 @@ export const Input = observer((props: Props) => {
}, [type]);
return (
-
+
{
onChange={handleInputChange}
/>
{isTouched && error ? : null}
-
+
);
});
diff --git a/src/ui/label.tsx b/src/ui/label.tsx
index cf535b2f..283983bc 100644
--- a/src/ui/label.tsx
+++ b/src/ui/label.tsx
@@ -1,6 +1,7 @@
import React, { ReactNode } from "react";
import { css } from "@emotion/css";
import { theme } from "./theme.tsx";
+import { Flex } from "./flex.tsx";
type Props = {
text: ReactNode;
@@ -17,7 +18,7 @@ export const Label = (props: Props) => {
return (
-
+
{props.text}
{props.isRequired && (
{
{slotRight}
)}
-
+
{props.children}
);