Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add top bar And improve Mobile view #42

Merged
merged 3 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -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");
Expand All @@ -24,7 +25,7 @@ function useRestoreLanguage() {
export default function App() {
const [colorSchemePreference] = useSetting("colorSchemePreference");
useRestoreLanguage();
const [sidebarMenuOpened, setSidebarMenuOpened] = useState<boolean>(false);
const [sidebarMenuOpened, sidebarhandlers] = useDisclosure(false);

const [registered] = useLocalStorage({
key: "registered",
Expand Down Expand Up @@ -53,17 +54,20 @@ export default function App() {
breakpoint: "xs",
collapsed: { mobile: !sidebarMenuOpened },
}}
header={{ height: 60 }}
>
<Header
menuOpened={sidebarMenuOpened}
menuHandlers={sidebarhandlers}
/>
<AppShell.Navbar>
<Sidebar
menuOpened={sidebarMenuOpened}
setMenuOpened={setSidebarMenuOpened}
menuHandlers={sidebarhandlers}
/>
</AppShell.Navbar>
<Main
menuOpened={sidebarMenuOpened}
setMenuOpened={setSidebarMenuOpened}
/>

<Main />
</AppShell>
) : (
<WelcomeView />
Expand Down
15 changes: 6 additions & 9 deletions src/components/CardManagerView/CardManagerView.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -32,14 +33,10 @@ function CardManagerView() {

return (
<Stack style={{ overflow: "hidden", width: "100%", height: "100%" }}>
<AppHeaderContent>
<Title order={3}>Manage Cards</Title>
</AppHeaderContent>
<Group align="end" gap="xs">
<ActionIcon
onClick={() => {
navigate(-1);
}}
>
<IconChevronLeft />
</ActionIcon>
<SelectDecksHeader label="Showing cards in" decks={decks} />
</Group>
<TextInput
Expand Down
49 changes: 35 additions & 14 deletions src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,44 @@
import classes from "./Header.module.css";
import React from "react";
import { ActionIcon } from "@mantine/core";
import React, { PropsWithChildren } from "react";
import { ActionIcon, AppShell, Burger, Group, Title } from "@mantine/core";
import { IconMenu2 } from "@tabler/icons-react";
import { createPortal } from "react-dom";

interface HeaderProps {
sidebarOpened: boolean;
setSidebarOpened: Function;
menuOpened: boolean;
menuHandlers: {
readonly open: () => 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 = () => (
<div id={APP_HEADER_OUTLET_NAME} style={{ flexGrow: 2 }} />
);

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 (
<ActionIcon
className={classes.icon}
onClick={() => setSidebarOpened(!sidebarOpened)}
>
<IconMenu2 />
</ActionIcon>
<AppShell.Header withBorder={false}>
<Group h="100%" px="md" p="lg" justify="flex-start">
<Burger
opened={menuOpened}
onClick={menuHandlers.toggle}
hiddenFrom="sm"
size="sm"
/>
<AppHeaderOutlet />
</Group>
</AppShell.Header>
);
}
48 changes: 18 additions & 30 deletions src/components/HomeView.tsx
Original file line number Diff line number Diff line change
@@ -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");
Expand All @@ -33,31 +27,25 @@ export default function HomeView({

return (
<>
<Stack gap="3rem" pt="lg" w="600px">
<Group>
{hasSmallScreen && (
<ActionIcon onClick={() => setMenuOpened(true)}>
<IconMenu2 />
</ActionIcon>
)}
<AppHeaderContent>
<Center>
<Title order={3}>
{userName
? t("home.welcome-user", { name: userName })
: t("home.welcome")}
</Title>
</Group>
</Center>
</AppHeaderContent>

<Stack gap="sm" align="flex-end" w="100%">
<Button
onClick={() => setNewDeckModalOpened(true)}
leftSection={<IconPlus />}
variant="default"
style={{ alignSelf: "align-end" }}
>
{t("deck.new-deck-button")}
</Button>
<DeckTable deckList={decks} isReady={isReady} />
</Stack>
<Stack gap="4rem" w="600px" maw="100%" align="flex-end">
<Button
onClick={() => setNewDeckModalOpened(true)}
leftSection={<IconPlus />}
variant="default"
>
{t("deck.new-deck-button")}
</Button>
<DeckTable deckList={decks} isReady={isReady} />
</Stack>
<NewDeckModal
opened={newDeckModalOpened}
Expand Down
7 changes: 0 additions & 7 deletions src/components/Main/Main.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,4 @@
height: 100%;
align-items: flex-start;
padding: var(--mantine-spacing-md);
padding-left: var(--mantine-spacing-md);
@mixin larger-than $mantine-breakpoint-xs {
padding-left: calc(var(--mantine-spacing-md) + 3.5rem);
}
@mixin larger-than $mantine-breakpoint-lg {
padding-left: calc(var(--mantine-spacing-md) + 18.75rem);
}
}
60 changes: 31 additions & 29 deletions src/components/Main/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,40 @@ import DeckView from "../deck/DeckView";
import NewCardView from "../editcard/NewCardsView";
import LearnView from "../learning/LearnView/LearnView";
import CardManagerView from "../CardManagerView/CardManagerView";
import { Center, Text } from "@mantine/core";
import { AppShell, Center, Text, Title } from "@mantine/core";
import React from "react";
import TodayView from "../TodayView";
export default function Main({
menuOpened,
setMenuOpened,
}: {
menuOpened: boolean;
setMenuOpened: Function;
}) {
import { AppHeaderContent } from "../Header/Header";

export default function Main() {
return (
<Center className={classes.main}>
<Routes>
<Route path="/" element={<Navigate to="/home" replace={true} />} />
<Route
path="/home"
element={
<HomeView menuOpened={menuOpened} setMenuOpened={setMenuOpened} />
}
/>
<Route path="/settings/*" element={<SettingsView />} />
<Route path="/deck/*" element={<DeckView />} />
<Route path="/new/*" element={<NewCardView />} />
<Route path="/learn/*" element={<LearnView />} />
<Route path="/cards/*" element={<CardManagerView />} />
<Route path="/today" element={<TodayView />} />
<AppShell.Main>
<Center className={classes.main}>
<Routes>
<Route path="/" element={<Navigate to="/home" replace={true} />} />
<Route path="/home" element={<HomeView />} />
<Route path="/settings/*" element={<SettingsView />} />
<Route path="/deck/*" element={<DeckView />} />
<Route path="/new/*" element={<NewCardView />} />
<Route path="/learn/*" element={<LearnView />} />
<Route path="/cards/*" element={<CardManagerView />} />
<Route path="/today" element={<TodayView />} />

<Route
path="/stats"
element={<Text>The statistics view is under development.</Text>}
/>
</Routes>
</Center>
<Route
path="/stats"
element={
<Text>
<AppHeaderContent>
<Center>
<Title order={3}>Statistics</Title>
</Center>
</AppHeaderContent>
The statistics view is under development.
</Text>
}
/>
</Routes>
</Center>
</AppShell.Main>
);
}
27 changes: 22 additions & 5 deletions src/components/SuperDecksBreadcrumbs/SuperDecksBreadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Box component="div" className={classes.wrapper} w={width / 3}>
<Box
component="div"
className={classes.wrapper}
w={width / 3}
style={{ flexGrow: 2 }}
>
<Breadcrumbs className={classes.breadcrumbs}>
<Anchor
key={0}
Expand All @@ -21,16 +30,24 @@ function SuperDecksBreadcrumbs({ superDecks }: SuperDecksBreadcrumbsProps) {
lh="1.5"
onClick={() => navigate("/home")}
>
Home
<Group wrap="nowrap">
<IconHome size="1em" /> {t("home.title")}
</Group>
</Anchor>
{superDecks?.map((s) => (
{superDecks?.map((s, idx) => (
<Anchor
key={s.id}
component="button"
type="button"
style={{
fontWeight: idx === superDecks.length - 1 ? "bold" : "normal",
color: idx === superDecks.length - 1 ? "red" : "blue",
}}
onClick={() => navigate("/deck/" + s.id)}
>
{s.name}
<Group wrap="nowrap">
<IconCardsFilled size="1rem" /> {s.name}
</Group>
</Anchor>
))}
</Breadcrumbs>
Expand Down
8 changes: 7 additions & 1 deletion src/components/TodayView.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Stack>
<AppHeaderContent>
<Title order={3}>
<Center>Today</Center>
</Title>
</AppHeaderContent>
The today view is a planned feature. Here you will be provided a feed of
upcoming decks that need to be reviewed.
</Stack>
Expand Down
Loading
Loading