diff --git a/src/App.tsx b/src/App.tsx index e37629d..d1e5d03 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,16 +1,17 @@ -import { AppShell, MantineProvider } from "@mantine/core"; +import { AppShell, Burger, Group, MantineProvider, Title } from "@mantine/core"; import "@mantine/core/styles.css"; import "@mantine/notifications/styles.css"; -import { useLocalStorage } from "@mantine/hooks"; +import { useDisclosure, useLocalStorage } from "@mantine/hooks"; import { Notifications } from "@mantine/notifications"; import { useEffect, useState } from "react"; import WelcomeView from "./components/WelcomeView"; -import { I18nextProvider } from "react-i18next"; +import { I18nextProvider, useTranslation } from "react-i18next"; import Main from "./components/Main/Main"; import Sidebar from "./components/sidebar/Sidebar"; import i18n from "./i18n"; import { useSetting } from "./logic/Settings"; import { cssVariablesResolver, presetTheme } from "./style/StyleProvider"; +import Header from "./components/Header/Header"; function useRestoreLanguage() { const [language] = useSetting("language"); @@ -24,7 +25,7 @@ function useRestoreLanguage() { export default function App() { const [colorSchemePreference] = useSetting("colorSchemePreference"); useRestoreLanguage(); - const [sidebarMenuOpened, setSidebarMenuOpened] = useState(false); + const [sidebarMenuOpened, sidebarhandlers] = useDisclosure(false); const [registered] = useLocalStorage({ key: "registered", @@ -53,17 +54,20 @@ export default function App() { breakpoint: "xs", collapsed: { mobile: !sidebarMenuOpened }, }} + header={{ height: 60 }} > +
-
+ +
) : ( diff --git a/src/components/CardManagerView/CardManagerView.tsx b/src/components/CardManagerView/CardManagerView.tsx index 6795e8a..8212e90 100644 --- a/src/components/CardManagerView/CardManagerView.tsx +++ b/src/components/CardManagerView/CardManagerView.tsx @@ -1,12 +1,13 @@ -import { ActionIcon, Group, Stack, TextInput } from "@mantine/core"; +import { Group, Stack, TextInput, Title } from "@mantine/core"; import { useDebouncedState } from "@mantine/hooks"; -import { IconChevronLeft, IconSearch } from "@tabler/icons-react"; +import { IconSearch } from "@tabler/icons-react"; import { useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import { Card, CardType, useCardsWith } from "../../logic/card"; import selectCards from "../../logic/card_filter"; import { useDecks } from "../../logic/deck"; import CardTable from "../CardTable/CardTable"; +import { AppHeaderContent } from "../Header/Header"; import SelectDecksHeader from "../custom/SelectDecksHeader"; import EditCardView from "../editcard/EditCardView"; import classes from "./CardManagerView.module.css"; @@ -32,14 +33,10 @@ function CardManagerView() { return ( + + Manage Cards + - { - navigate(-1); - }} - > - - void; + readonly close: () => void; + readonly toggle: () => void; + }; } -export default function Header({ - sidebarOpened, - setSidebarOpened, -}: HeaderProps) { +export const APP_HEADER_OUTLET_NAME = "APP_HEADER_OUTLET"; + +export const AppHeaderOutlet = () => ( +
+); + +export const AppHeaderContent = ({ children }: PropsWithChildren) => { + const element = document.getElementById( + APP_HEADER_OUTLET_NAME + ) as HTMLElement; + return element && createPortal(children, element); +}; + +export default function Header({ menuOpened, menuHandlers }: HeaderProps) { + console.log("Header"); return ( - setSidebarOpened(!sidebarOpened)} - > - - + + + + + + ); } diff --git a/src/components/HomeView.tsx b/src/components/HomeView.tsx index 4555c53..b248b58 100644 --- a/src/components/HomeView.tsx +++ b/src/components/HomeView.tsx @@ -1,30 +1,24 @@ import { ActionIcon, Button, + Center, Group, Stack, Title, useMantineTheme, } from "@mantine/core"; -import { IconMenu2, IconPlus } from "@tabler/icons-react"; +import { IconPlus } from "@tabler/icons-react"; import { useState } from "react"; import NewDeckModal from "./deck/NewDeckModal"; import DeckTable from "./deck/DeckTable"; import { useTopLevelDecks } from "../logic/deck"; import { useSetting } from "../logic/Settings"; -import { useHotkeys, useMediaQuery } from "@mantine/hooks"; +import { useHotkeys } from "@mantine/hooks"; import { useTranslation } from "react-i18next"; +import { AppHeaderContent } from "./Header/Header"; -export default function HomeView({ - setMenuOpened, -}: { - menuOpened: boolean; - setMenuOpened: Function; -}) { - const theme = useMantineTheme(); +export default function HomeView({}: {}) { const [t] = useTranslation(); - const hasSmallScreen = useMediaQuery(`(max-width: ${theme.breakpoints.xs})`); - const [newDeckModalOpened, setNewDeckModalOpened] = useState(false); const [decks, isReady] = useTopLevelDecks(); const [userName] = useSetting("name"); @@ -33,31 +27,25 @@ export default function HomeView({ return ( <> - - - {hasSmallScreen && ( - setMenuOpened(true)}> - - - )} + +
{userName ? t("home.welcome-user", { name: userName }) : t("home.welcome")} - +
+
- - - - + + + - - } /> - - } - /> - } /> - } /> - } /> - } /> - } /> - } /> + +
+ + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> - The statistics view is under development.} - /> - -
+ + +
+ Statistics +
+
+ The statistics view is under development. + + } + /> +
+ + ); } diff --git a/src/components/SuperDecksBreadcrumbs/SuperDecksBreadcrumbs.tsx b/src/components/SuperDecksBreadcrumbs/SuperDecksBreadcrumbs.tsx index 3ac2136..ff2ae83 100644 --- a/src/components/SuperDecksBreadcrumbs/SuperDecksBreadcrumbs.tsx +++ b/src/components/SuperDecksBreadcrumbs/SuperDecksBreadcrumbs.tsx @@ -1,18 +1,27 @@ import classes from "./SuperDecksBreadcrumbs.module.css"; import React from "react"; -import { Anchor, Box, Breadcrumbs } from "@mantine/core"; +import { Anchor, Box, Breadcrumbs, Group, Title } from "@mantine/core"; import { Deck } from "../../logic/deck"; import { useNavigate } from "react-router-dom"; import { useViewportSize } from "@mantine/hooks"; +import { useTranslation } from "react-i18next"; +import { IconHome, IconCardsFilled } from "@tabler/icons-react"; interface SuperDecksBreadcrumbsProps { superDecks: Deck[] | undefined; } function SuperDecksBreadcrumbs({ superDecks }: SuperDecksBreadcrumbsProps) { const navigate = useNavigate(); + const [t] = useTranslation(); const { width } = useViewportSize(); + return ( - + navigate("/home")} > - Home + + {t("home.title")} + - {superDecks?.map((s) => ( + {superDecks?.map((s, idx) => ( navigate("/deck/" + s.id)} > - {s.name} + + {s.name} + ))} diff --git a/src/components/TodayView.tsx b/src/components/TodayView.tsx index 2d002a1..14bf4ab 100644 --- a/src/components/TodayView.tsx +++ b/src/components/TodayView.tsx @@ -1,9 +1,15 @@ import React from "react"; -import { Stack } from "@mantine/core"; +import { Center, Stack, Title } from "@mantine/core"; +import { AppHeaderContent } from "./Header/Header"; function TodayView({}: {}) { return ( + + + <Center>Today</Center> + + The today view is a planned feature. Here you will be provided a feed of upcoming decks that need to be reviewed. diff --git a/src/components/deck/DeckMenu.tsx b/src/components/deck/DeckMenu.tsx index 35f110f..141cda7 100644 --- a/src/components/deck/DeckMenu.tsx +++ b/src/components/deck/DeckMenu.tsx @@ -19,6 +19,7 @@ import { Card, CardType } from "../../logic/card"; import { useSetting } from "../../logic/Settings"; import ImportModal from "../settings/importexport/ImportModal"; import { useHotkeys } from "@mantine/hooks"; +import { useTranslation } from "react-i18next"; interface DeckMenuProps { deck?: Deck; @@ -36,6 +37,7 @@ function DeckMenu({ areCardsReady, }: DeckMenuProps) { const navigate = useNavigate(); + const [t] = useTranslation(); const [developerMode] = useSetting("developerMode"); @@ -68,6 +70,8 @@ function DeckMenu({ diff --git a/src/components/deck/DeckView.tsx b/src/components/deck/DeckView.tsx index 890178d..13ed183 100644 --- a/src/components/deck/DeckView.tsx +++ b/src/components/deck/DeckView.tsx @@ -1,7 +1,17 @@ import React, { useState } from "react"; -import { ActionIcon, Button, Group, Stack, Title, Text } from "@mantine/core"; +import { + ActionIcon, + Button, + Group, + Stack, + Title, + Center, + useMantineTheme, + Space, + Text, +} from "@mantine/core"; import SubDeckSection from "./SubDeckSection"; -import { IconChevronLeft, IconPlus } from "@tabler/icons-react"; +import { IconPlus } from "@tabler/icons-react"; import DeckMenu from "./DeckMenu"; import { useNavigate } from "react-router-dom"; import { useDeckFromUrl, useSuperDecks } from "../../logic/deck"; @@ -13,15 +23,17 @@ import HeroDeckSection from "./HeroDeckSection/HeroDeckSection"; import { useDocumentTitle, useHotkeys } from "@mantine/hooks"; import { useScrollResetOnLocationChange } from "../../logic/ui"; import NotebookView from "../notebook/NotebookView"; +import { AppHeaderContent } from "../Header/Header"; +import { IconChevronLeft } from "@tabler/icons-react"; function DeckView() { const navigate = useNavigate(); + const theme = useMantineTheme(); const [deckOptionsOpened, setDeckOptionsOpened] = useState(false); const [deck, isDeckReady] = useDeckFromUrl(); const [superDecks] = useSuperDecks(deck); const [cards, areCardsReady] = useCardsOf(deck); - useScrollResetOnLocationChange(); useDocumentTitle(deck?.name ? deck?.name : "Skola"); @@ -31,41 +43,9 @@ function DeckView() { return ( <> - - - - - navigate( - deck && - deck.superDecks && - deck.superDecks[deck.superDecks.length - 1] - ? "/deck/" + deck.superDecks[deck.superDecks.length - 1] - : "/home" - ) - } - > - - - - - - {deck && deck.name} - - - - + + + - - {deck && deck.description && ( - - )} + + + + + {deck?.name} + + + { if (location.pathname === "/settings") { @@ -37,11 +36,11 @@ export default function SettingsView() { return ( - - navigate(-1)}> - - - + +
+ {t("settings.page-title")} +
+
void; + readonly close: () => void; + readonly toggle: () => void; + }; }) { const location = useLocation(); const navigate = useNavigate(); @@ -76,14 +80,14 @@ function Sidebar({ leftSection={icon} onClick={() => { navigate(path); - fullscreenMode && setMenuOpened(false); + fullscreenMode && menuHandlers.close(); }} active={location.pathname.startsWith(path)} /> ); }, - [location.pathname, navigate, setMenuOpened, fullscreenMode] + [location.pathname, navigate, menuHandlers, fullscreenMode] ); const fullScreen = { @@ -114,7 +118,7 @@ function Sidebar({
{fullscreenMode ? ( setMenuOpened(false)} + onClick={() => menuHandlers.close()} style={{ alignSelf: "end" }} > diff --git a/src/i18n/locales/de/translation.json b/src/i18n/locales/de/translation.json index 736bce0..4364c3e 100644 --- a/src/i18n/locales/de/translation.json +++ b/src/i18n/locales/de/translation.json @@ -29,6 +29,7 @@ "language-description": "Ändere die Sprache der Benutzeroberfläche.", "title": "Allgemein" }, + "page-title": "", "appearance": { "title": "Erscheinungsbild" }, diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json index c7ec14f..e077465 100644 --- a/src/i18n/locales/en/translation.json +++ b/src/i18n/locales/en/translation.json @@ -9,11 +9,13 @@ "new-cards-label": "New", "learning-cards-label": "Learning", "review-cards-label": "Review", - "new-deck-button": "New Deck" + "new-deck-button": "New Deck", + "settings": "Settings" }, "home": { "welcome-user": "Welcome back, {{name}}!", - "welcome": "Welcome!" + "welcome": "Welcome!", + "title": "Home" }, "settings": { "about": { @@ -29,6 +31,7 @@ "language-description": "Set the language for the user interface.", "title": "General" }, + "page-title": "Settings", "appearance": { "title": "Appearance" }, diff --git a/src/i18n/locales/sv/translation.json b/src/i18n/locales/sv/translation.json index e517b68..476355b 100644 --- a/src/i18n/locales/sv/translation.json +++ b/src/i18n/locales/sv/translation.json @@ -29,6 +29,7 @@ "language-description": "Språk som används i gränssnittet.", "title": "General" }, + "page-title": "", "appearance": { "title": "Utseende" },