diff --git a/src/components/ExpressionSetCard/index.tsx b/src/components/ExpressionSetCard/index.ts similarity index 100% rename from src/components/ExpressionSetCard/index.tsx rename to src/components/ExpressionSetCard/index.ts diff --git a/src/components/Navigation/NavigationItem.tsx b/src/components/Navigation/NavigationItem.tsx index d39b619..d8e4be1 100644 --- a/src/components/Navigation/NavigationItem.tsx +++ b/src/components/Navigation/NavigationItem.tsx @@ -1,7 +1,6 @@ import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/router"; -import { UrlObject } from "url"; export interface NavigationItemProps { text: string; diff --git a/src/components/Navigation/index.tsx b/src/components/Navigation/index.ts similarity index 100% rename from src/components/Navigation/index.tsx rename to src/components/Navigation/index.ts diff --git a/src/components/Page/Page.stories.tsx b/src/components/Page/Page.stories.tsx index c0e4a13..a891998 100644 --- a/src/components/Page/Page.stories.tsx +++ b/src/components/Page/Page.stories.tsx @@ -5,7 +5,6 @@ import React from "react"; import { ComponentStory, ComponentMeta } from "@storybook/react"; import { Page } from "./Page"; -import { Navigation, NavigationItem } from "../Navigation"; export default { title: "Components/Page", @@ -13,7 +12,7 @@ export default { } as ComponentMeta; export const Example: ComponentStory = (args) => ( - +
Content goes here
diff --git a/src/components/index.ts b/src/components/index.ts index 45c6538..7da765b 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,2 +1,5 @@ export * from "./ExpressionCard"; +export * from "./ExpressionSetCard"; +export * from "./ExpressionSetInfo"; export * from "./Navigation"; +export * from "./Page"; diff --git a/src/hooks/index.ts b/src/hooks/index.ts new file mode 100644 index 0000000..2158ec8 --- /dev/null +++ b/src/hooks/index.ts @@ -0,0 +1,6 @@ +export * from "./useExpressionCategories"; +export * from "./useExpressionFilterQueryIds"; +export * from "./useExpressionSet"; +export * from "./useExpressionSetQueryId"; +export * from "./useExpressionSets"; +export * from "./useExpressionsInSet"; diff --git a/src/hooks/useExpressionCategories.ts b/src/hooks/useExpressionCategories.ts index 8319772..96052a6 100644 --- a/src/hooks/useExpressionCategories.ts +++ b/src/hooks/useExpressionCategories.ts @@ -2,15 +2,13 @@ import { useLiveQuery } from "dexie-react-hooks"; import { database } from "../model"; export function useExpressionCategories(expression_id: number) { - return ( - useLiveQuery(() => { - return database.expression_to_category - .where({ expression_id }) - .toArray() - .then((relationships) => { - const category_ids = relationships.map((item) => item.category_id); - return database.categories.where("id").anyOf(category_ids).toArray(); - }); - }, [expression_id]) || [] - ); + return useLiveQuery(() => { + return database.expression_to_category + .where({ expression_id }) + .toArray() + .then((relationships) => { + const category_ids = relationships.map((item) => item.category_id); + return database.categories.where("id").anyOf(category_ids).toArray(); + }); + }, [expression_id]); } diff --git a/src/hooks/useExpressionSets.ts b/src/hooks/useExpressionSets.ts index b8aa79a..280a4fc 100644 --- a/src/hooks/useExpressionSets.ts +++ b/src/hooks/useExpressionSets.ts @@ -1,6 +1,6 @@ import { useLiveQuery } from "dexie-react-hooks"; -import { database, IndexedExpressionSet } from "../model"; +import { database } from "../model"; export function useExpressionSets() { - return useLiveQuery(() => database.expression_sets.toArray()) || []; + return useLiveQuery(() => database.expression_sets.toArray()); } diff --git a/src/hooks/useExpressionsInSet.ts b/src/hooks/useExpressionsInSet.ts index 371acfc..c4d77a6 100644 --- a/src/hooks/useExpressionsInSet.ts +++ b/src/hooks/useExpressionsInSet.ts @@ -2,20 +2,13 @@ import { useLiveQuery } from "dexie-react-hooks"; import { database } from "../model"; export function useExpressionsInSet(expression_set_id: number) { - return ( - useLiveQuery(() => { - return database.expression_to_expression_set - .where({ expression_set_id }) - .toArray() - .then((relationships) => { - const expression_ids = relationships.map( - (item) => item.expression_id - ); - return database.expressions - .where("id") - .anyOf(expression_ids) - .toArray(); - }); - }, [expression_set_id]) || [] - ); + return useLiveQuery(() => { + return database.expression_to_expression_set + .where({ expression_set_id }) + .toArray() + .then((relationships) => { + const expression_ids = relationships.map((item) => item.expression_id); + return database.expressions.where("id").anyOf(expression_ids).toArray(); + }); + }, [expression_set_id]); } diff --git a/src/mock/index.ts b/src/mock/index.ts deleted file mode 100644 index 94b9574..0000000 --- a/src/mock/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./mock-data"; diff --git a/src/mock/mock-data.ts b/src/mock/mock-data.ts index 24d6073..84f3d6d 100644 --- a/src/mock/mock-data.ts +++ b/src/mock/mock-data.ts @@ -4,7 +4,7 @@ import { ExpressionSet, ExpressionToCategory, ExpressionToExpressionSet, -} from "../model"; +} from "../model/types"; interface RawExpressionDataItem { prompt: string; diff --git a/src/model/database.ts b/src/model/database.ts index 2466a02..a08e348 100644 --- a/src/model/database.ts +++ b/src/model/database.ts @@ -1,5 +1,5 @@ +import { MockData } from "../mock/mock-data"; import Dexie, { Table } from "dexie"; -import { MockData } from "../mock"; import { Category, Expression, diff --git a/src/model/index.ts b/src/model/index.ts index 031f1be..650d00f 100644 --- a/src/model/index.ts +++ b/src/model/index.ts @@ -1,2 +1,2 @@ -export * from "./types"; export * from "./database"; +export * from "./types"; diff --git a/src/pages/404.tsx b/src/pages/404.tsx index c32f5f5..c8a666e 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -1,10 +1,10 @@ import type { NextPage } from "next"; -import { PageWithError } from "../views/PageWithError"; +import { ErrorView } from "../views"; const PageTitle = "Flash Card App - 404"; const Page404: NextPage = () => { - return ; + return ; }; export default Page404; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 22f6f7c..80976d1 100755 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -3,7 +3,7 @@ import "../styles/components.css"; import type { AppProps } from "next/app"; import { Navigation } from "../components"; -export default function MyApp({ Component, pageProps }: AppProps) { +export default function FlashCardApp({ Component, pageProps }: AppProps) { return (
diff --git a/src/pages/expression-sets/details.tsx b/src/pages/expression-sets/details.tsx index 5039f2a..d7f0ddc 100644 --- a/src/pages/expression-sets/details.tsx +++ b/src/pages/expression-sets/details.tsx @@ -1,12 +1,13 @@ import type { NextPage } from "next"; import dynamic from "next/dynamic"; import Link from "next/link"; -import { ExpressionSetInfo } from "../../components/ExpressionSetInfo/ExpressionSetInfo"; -import { Page } from "../../components/Page"; -import { useExpressionSet } from "../../hooks/useExpressionSet"; -import { useExpressionSetQueryId } from "../../hooks/useExpressionSetQueryId"; -import { useExpressionsInSet } from "../../hooks/useExpressionsInSet"; -import { PageWithError } from "../../views/PageWithError/PageWithError"; +import { ExpressionSetInfo, Page } from "../../components"; +import { + useExpressionSet, + useExpressionSetQueryId, + useExpressionsInSet, +} from "../../hooks"; +import { ErrorView, ExpressionSetDetailsView } from "../../views"; function pageTitle(name?: string) { return `Flash Card App - ${name || "Sets"}`; @@ -18,53 +19,18 @@ const ExpressionSetDetailsPage: NextPage = () => { const expressions = useExpressionsInSet(expression_set_id); // Fallback for expression set not found + if (!expressions) return null; if (!expression_set) { - return ( - - ); + return ; } // Fallback for expression set empty - if (expressions.length === 0) - return ( - -
- -

No expressions left in this set.

-
-
- ); - return ( -
-
- -
-
- - - Practice this set - - -
-
+
); }; diff --git a/src/pages/expression-sets/index.tsx b/src/pages/expression-sets/index.tsx index d2b8326..0ee18ed 100644 --- a/src/pages/expression-sets/index.tsx +++ b/src/pages/expression-sets/index.tsx @@ -1,61 +1,25 @@ import type { NextPage } from "next"; import dynamic from "next/dynamic"; -import Link from "next/link"; -import { ExpressionSetCard } from "../../components/ExpressionSetCard"; -import { Page } from "../../components/Page"; -import { useExpressionSets } from "../../hooks/useExpressionSets"; -import { useExpressionsInSet } from "../../hooks/useExpressionsInSet"; -import { IndexedExpressionSet } from "../../model"; -import { PageWithError } from "../../views/PageWithError"; +import { Page } from "../../components"; +import { useExpressionSets } from "../../hooks"; +import { ErrorView, ExpressionSetListView } from "../../views"; const PageTitle = "Flash Card App - Sets"; const ExpressionSetListPage: NextPage = () => { const expression_sets = useExpressionSets(); - - if (!expression_sets?.length) { - return ( - - ); + if (!expression_sets) return null; + if (!expression_sets.length) { + return ; } return ( -
- {expression_sets.map(({ id, name, description }) => ( - - ))} -
+
); }; -function ExpressionSetLink({ id, description, name }: IndexedExpressionSet) { - const expressions = useExpressionsInSet(id!) || []; - return ( - - - - - - ); -} - export default dynamic(() => Promise.resolve(ExpressionSetListPage), { ssr: false, }); diff --git a/src/pages/expression-sets/practice.tsx b/src/pages/expression-sets/practice.tsx index 2f1c1f0..f1e789e 100644 --- a/src/pages/expression-sets/practice.tsx +++ b/src/pages/expression-sets/practice.tsx @@ -1,162 +1,44 @@ -import type { NextPage } from "next"; +import { NextPage } from "next"; import dynamic from "next/dynamic"; -import { useRouter } from "next/router"; -import { useCallback, useMemo, useState } from "react"; -import { ExpressionCard } from "../../components"; -import { Page } from "../../components/Page"; -import { useExpressionCategories } from "../../hooks/useExpressionCategories"; -import { useExpressionFilterQueryIds } from "../../hooks/useExpressionFilterQueryIds"; -import { useExpressionSetQueryId } from "../../hooks/useExpressionSetQueryId"; -import { useExpressionsInSet } from "../../hooks/useExpressionsInSet"; +import { Page } from "../../components"; import { - assignExpressionToSet, - IndexedCategory, - IndexedExpression, -} from "../../model"; -import { sample } from "../../util/array-utils"; -import { PageWithError } from "../../views/PageWithError/PageWithError"; + useExpressionFilterQueryIds, + useExpressionSetQueryId, + useExpressionsInSet, +} from "../../hooks"; +import { ErrorView } from "../../views"; +import { ExpressionPracticeView } from "../../views"; const PageTitle = "Flash Card App - Practice"; -// Do random selection here so we don't keep flipping states with interaction const ExpressionPracticePage: NextPage = () => { - // Query info const expression_set_id = useExpressionSetQueryId(); const filter_ids = useExpressionFilterQueryIds(); + const expressions = useExpressionsInSet(expression_set_id); - // Filter out failed expressions and select random expression - const expressions = useExpressionsInSet(expression_set_id).filter( - (expression) => !filter_ids.includes(expression.id!) - ); - const expression: IndexedExpression | undefined = useMemo( - () => (expressions ? sample(expressions) : undefined), - [expressions] - ); - - // Fetch categories that the expression relates to - const categories = useExpressionCategories(expression?.id || 0); + // Fallback rendering for content not yet fetched + if (!expressions) return null; + if (!filter_ids) return null; // Fallback views for expression set content not found if (!expression_set_id) { - return ( - - ); + return ; } - if (!expression) { - return ( - - ); - } - - return ( - + const filtered_expressions = expressions.filter( + (expression) => !filter_ids.includes(expression.id!) ); -}; + if (!filtered_expressions.length) { + return ( + + ); + } -interface ExpressionCardPracticeViewProps { - expression: IndexedExpression; - categories: IndexedCategory[]; -} - -// Handle internal state here -function ExpressionCardPracticeView({ - expression, - categories, -}: ExpressionCardPracticeViewProps) { - const [revealed, setRevealed] = useState(false); return ( -
-
- category.name)} - description={expression.description} - show_description={revealed} - /> -
-
- {revealed ? ( - <> - - - - ) : ( - - )} -
-
+
); -} - -interface ExpressionIdProps { - expression_id: number; -} - -function PromoteExpressionButton({ expression_id }: ExpressionIdProps) { - const expression_set_id = useExpressionSetQueryId(); - const handleClick = useCallback(() => { - assignExpressionToSet({ - expression_id, - expression_set_id: expression_set_id + 1, - }); - }, [expression_id, expression_set_id]); - - return ( - - ); -} - -function DemoteExpressionButton({ expression_id }: ExpressionIdProps) { - const { query, pathname, push } = useRouter(); - const expression_set_id = useExpressionSetQueryId(); - const handleClick = useCallback(() => { - if (expression_set_id === 1) { - const filter_ids = query["filter-ids"] - ? `${query["filter-ids"]} ${expression_id}` - : `${expression_id}`; - push({ - pathname, - query: { - ...query, - "filter-ids": filter_ids, - }, - }); - } else { - assignExpressionToSet({ - expression_id, - expression_set_id: Math.max(1, expression_set_id - 1), - }); - } - }, [expression_id, expression_set_id, pathname, push, query]); - - return ( - - ); -} +}; export default dynamic(() => Promise.resolve(ExpressionPracticePage), { ssr: false, diff --git a/src/pages/index.tsx b/src/pages/index.tsx index e892539..2737bc6 100755 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,5 +1,5 @@ import type { NextPage } from "next"; -import { Page } from "../components/Page"; +import { Page } from "../components"; const PageTitle = "Flash Card App"; diff --git a/src/util/data-utils.ts b/src/util/data-utils.ts deleted file mode 100644 index 774fdda..0000000 --- a/src/util/data-utils.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - Category, - Expression, - ExpressionToCategory, - ExpressionToExpressionSet, -} from "../model"; - -interface GetExpressionsInSetParams { - expression_set_id: number; - expressions: Expression[]; - expression_to_expression_set: ExpressionToExpressionSet[]; -} - -export function getExpressionsInSet({ - expression_set_id, - expression_to_expression_set, - expressions, -}: GetExpressionsInSetParams): Expression[] { - const expression_ids = expression_to_expression_set - .filter((item) => item.expression_set_id === expression_set_id) - .map((item) => item.expression_id); - return expressions.filter((item) => expression_ids.includes(item.id)); -} - -interface GetCategoriesInExpressionParams { - expression_id: number; - categories: Category[]; - expression_to_category: ExpressionToCategory[]; -} - -export function getCategoriesInExpression({ - categories, - expression_id, - expression_to_category, -}: GetCategoriesInExpressionParams) { - const category_ids = expression_to_category - .filter((item) => item.expression_id === expression_id) - .map((item) => item.category_id); - return categories.filter((item) => category_ids.includes(item.id)); -} diff --git a/src/util/index.ts b/src/util/index.ts new file mode 100644 index 0000000..02e18a4 --- /dev/null +++ b/src/util/index.ts @@ -0,0 +1,2 @@ +export * from "./array-utils"; +export * from "./clamp"; diff --git a/src/views/PageWithError/PageWithError.tsx b/src/views/ErrorView/ErrorView.tsx similarity index 68% rename from src/views/PageWithError/PageWithError.tsx rename to src/views/ErrorView/ErrorView.tsx index 05f1f2a..0ce50f6 100644 --- a/src/views/PageWithError/PageWithError.tsx +++ b/src/views/ErrorView/ErrorView.tsx @@ -1,11 +1,11 @@ import { Page } from "../../components/Page"; -export interface PageWithErrorProps { +export interface ErrorViewProps { title: string; message: string; } -export function PageWithError({ title, message }: PageWithErrorProps) { +export function ErrorView({ title, message }: ErrorViewProps) { return (
diff --git a/src/views/ErrorView/index.ts b/src/views/ErrorView/index.ts new file mode 100644 index 0000000..c1ca494 --- /dev/null +++ b/src/views/ErrorView/index.ts @@ -0,0 +1 @@ +export * from "./ErrorView"; diff --git a/src/views/ExpressionPracticeView/DemoteExpressionButton.tsx b/src/views/ExpressionPracticeView/DemoteExpressionButton.tsx new file mode 100644 index 0000000..a728a2d --- /dev/null +++ b/src/views/ExpressionPracticeView/DemoteExpressionButton.tsx @@ -0,0 +1,45 @@ +import { useRouter } from "next/router"; +import { useCallback } from "react"; +import { useExpressionSetQueryId } from "../../hooks"; +import { assignExpressionToSet } from "../../model"; + +// TODO fix promotion algorithm so it uses a destination expression_set_id + +export interface DemoteExpressionButtonProps { + expression_id: number; +} + +export function DemoteExpressionButton({ + expression_id, +}: DemoteExpressionButtonProps) { + const { query, pathname, push } = useRouter(); + const expression_set_id = useExpressionSetQueryId(); + const handleClick = useCallback(() => { + if (expression_set_id === 1) { + const filter_ids = query["filter-ids"] + ? `${query["filter-ids"]} ${expression_id}` + : `${expression_id}`; + push({ + pathname, + query: { + ...query, + "filter-ids": filter_ids, + }, + }); + } else { + assignExpressionToSet({ + expression_id, + expression_set_id: Math.max(1, expression_set_id - 1), + }); + } + }, [expression_id, expression_set_id, pathname, push, query]); + + return ( + + ); +} diff --git a/src/views/ExpressionPracticeView/ExpressionPracticeCardView.tsx b/src/views/ExpressionPracticeView/ExpressionPracticeCardView.tsx new file mode 100644 index 0000000..d97fcef --- /dev/null +++ b/src/views/ExpressionPracticeView/ExpressionPracticeCardView.tsx @@ -0,0 +1,45 @@ +import { useState } from "react"; +import { ExpressionCard } from "../../components"; +import { IndexedExpression, IndexedCategory } from "../../model"; +import { DemoteExpressionButton } from "./DemoteExpressionButton"; +import { PromoteExpressionButton } from "./PromoteExpressionButton"; + +export interface ExpressionPracticeCardViewProps { + expression: IndexedExpression; + categories: IndexedCategory[]; +} + +// Handle internal state here +export function ExpressionPracticeCardView({ + expression, + categories, +}: ExpressionPracticeCardViewProps) { + const [revealed, setRevealed] = useState(false); + return ( +
+
+ category.name)} + description={expression.description} + show_description={revealed} + /> +
+
+ {revealed ? ( + <> + + + + ) : ( + + )} +
+
+ ); +} diff --git a/src/views/ExpressionPracticeView/ExpressionPracticeView.tsx b/src/views/ExpressionPracticeView/ExpressionPracticeView.tsx new file mode 100644 index 0000000..1b11dee --- /dev/null +++ b/src/views/ExpressionPracticeView/ExpressionPracticeView.tsx @@ -0,0 +1,27 @@ +import { useMemo } from "react"; +import { useExpressionCategories } from "../../hooks"; +import { IndexedExpression } from "../../model"; +import { sample } from "../../util"; +import { ExpressionPracticeCardView } from "./ExpressionPracticeCardView"; + +export interface ExpressionPracticeViewProps { + select_from_expressions: IndexedExpression[]; +} + +export function ExpressionPracticeView({ + select_from_expressions: expressions, +}: ExpressionPracticeViewProps) { + const expression = useMemo(() => sample(expressions), [expressions]); + const categories = useExpressionCategories(expression.id!); + if (!categories) return null; + + // Delegate internal interaction state to next component so it resets + // on an expression switch + return ( + + ); +} diff --git a/src/views/ExpressionPracticeView/PromoteExpressionButton.tsx b/src/views/ExpressionPracticeView/PromoteExpressionButton.tsx new file mode 100644 index 0000000..8b7d6b2 --- /dev/null +++ b/src/views/ExpressionPracticeView/PromoteExpressionButton.tsx @@ -0,0 +1,30 @@ +import { useCallback } from "react"; +import { useExpressionSetQueryId } from "../../hooks"; +import { assignExpressionToSet } from "../../model"; + +// TODO fix promotion algorithm so it uses a destination expression_set_id + +export interface PromoteExpressionButtonProps { + expression_id: number; +} + +export function PromoteExpressionButton({ + expression_id, +}: PromoteExpressionButtonProps) { + const expression_set_id = useExpressionSetQueryId(); + const handleClick = useCallback(() => { + assignExpressionToSet({ + expression_id, + expression_set_id: expression_set_id + 1, + }); + }, [expression_id, expression_set_id]); + + return ( + + ); +} diff --git a/src/views/ExpressionPracticeView/index.ts b/src/views/ExpressionPracticeView/index.ts new file mode 100644 index 0000000..fb01f42 --- /dev/null +++ b/src/views/ExpressionPracticeView/index.ts @@ -0,0 +1 @@ +export * from "./ExpressionPracticeView"; diff --git a/src/views/ExpressionSetDetailsView/ExpressionSetDetailsView.tsx b/src/views/ExpressionSetDetailsView/ExpressionSetDetailsView.tsx new file mode 100644 index 0000000..b90f6ae --- /dev/null +++ b/src/views/ExpressionSetDetailsView/ExpressionSetDetailsView.tsx @@ -0,0 +1,53 @@ +import Link from "next/link"; +import { ExpressionSetInfo } from "../../components"; +import { IndexedExpressionSet } from "../../model"; + +export interface ExpressionSetDetailsViewProps { + expression_set: IndexedExpressionSet; + expression_count: number; +} + +export function ExpressionSetDetailsView({ + expression_set, + expression_count, +}: ExpressionSetDetailsViewProps) { + if (!expression_count) { + return ( +
+ +

No expressions left in this set.

+
+ ); + } + + return ( +
+
+ +
+
+ + + Practice this set + + +
+
+ ); +} diff --git a/src/views/ExpressionSetDetailsView/index.ts b/src/views/ExpressionSetDetailsView/index.ts new file mode 100644 index 0000000..24780d3 --- /dev/null +++ b/src/views/ExpressionSetDetailsView/index.ts @@ -0,0 +1 @@ +export * from "./ExpressionSetDetailsView"; diff --git a/src/views/ExpressionSetListView/ExpressionSetLink.tsx b/src/views/ExpressionSetListView/ExpressionSetLink.tsx new file mode 100644 index 0000000..8fd1a9d --- /dev/null +++ b/src/views/ExpressionSetListView/ExpressionSetLink.tsx @@ -0,0 +1,30 @@ +import Link from "next/link"; +import { ExpressionSetCard } from "../../components"; +import { useExpressionsInSet } from "../../hooks"; +import { IndexedExpressionSet } from "../../model"; + +export function ExpressionSetLink({ + id, + description, + name, +}: IndexedExpressionSet) { + const expressions = useExpressionsInSet(id!) || []; + + return ( + + + + + + ); +} diff --git a/src/views/ExpressionSetListView/ExpressionSetListView.tsx b/src/views/ExpressionSetListView/ExpressionSetListView.tsx new file mode 100644 index 0000000..8e133d3 --- /dev/null +++ b/src/views/ExpressionSetListView/ExpressionSetListView.tsx @@ -0,0 +1,23 @@ +import { IndexedExpressionSet } from "../../model"; +import { ExpressionSetLink } from "./ExpressionSetLink"; + +export interface ExpressionSetListViewProps { + expression_sets: IndexedExpressionSet[]; +} + +export function ExpressionSetListView({ + expression_sets, +}: ExpressionSetListViewProps) { + return ( +
+ {expression_sets.map(({ id, name, description }) => ( + + ))} +
+ ); +} diff --git a/src/views/ExpressionSetListView/index.ts b/src/views/ExpressionSetListView/index.ts new file mode 100644 index 0000000..9e75d86 --- /dev/null +++ b/src/views/ExpressionSetListView/index.ts @@ -0,0 +1 @@ +export * from "./ExpressionSetListView"; diff --git a/src/views/PageWithError/index.ts b/src/views/PageWithError/index.ts deleted file mode 100644 index 1ac8772..0000000 --- a/src/views/PageWithError/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./PageWithError"; diff --git a/src/views/index.ts b/src/views/index.ts new file mode 100644 index 0000000..5f5427e --- /dev/null +++ b/src/views/index.ts @@ -0,0 +1,4 @@ +export * from "./ErrorView"; +export * from "./ExpressionPracticeView"; +export * from "./ExpressionSetDetailsView"; +export * from "./ExpressionSetListView";