aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FrontEnd/src/app/index.sass5
-rw-r--r--FrontEnd/src/app/views/common/AppBar.tsx124
-rw-r--r--FrontEnd/src/app/views/common/common.sass84
3 files changed, 142 insertions, 71 deletions
diff --git a/FrontEnd/src/app/index.sass b/FrontEnd/src/app/index.sass
index 329248b8..2df5c726 100644
--- a/FrontEnd/src/app/index.sass
+++ b/FrontEnd/src/app/index.sass
@@ -16,8 +16,9 @@
@import './views/admin/admin'
:root
- --primary-color: #007bff
- --text-on-primary-color: #ffffff
+ --tl-primary-color: #007bff
+ --tl-text-on-primary-color: #ffffff
+ --tl-text-inactive-on-primary-color: rgb(255 255 255 / 75%)
small
line-height: 1.2
diff --git a/FrontEnd/src/app/views/common/AppBar.tsx b/FrontEnd/src/app/views/common/AppBar.tsx
index 939f0175..91dfbee9 100644
--- a/FrontEnd/src/app/views/common/AppBar.tsx
+++ b/FrontEnd/src/app/views/common/AppBar.tsx
@@ -1,8 +1,8 @@
import React from "react";
import { useTranslation } from "react-i18next";
-import { LinkContainer } from "react-router-bootstrap";
-import { Navbar, Nav } from "react-bootstrap";
-import { NavLink } from "react-router-dom";
+import { Link, NavLink } from "react-router-dom";
+import classnames from "classnames";
+import { useMediaQuery } from "react-responsive";
import { useUser } from "@/services/user";
@@ -10,84 +10,70 @@ import TimelineLogo from "./TimelineLogo";
import UserAvatar from "./user/UserAvatar";
const AppBar: React.FC = (_) => {
- const user = useUser();
-
const { t } = useTranslation();
+ const user = useUser();
const hasAdministrationPermission = user && user.hasAdministrationPermission;
+ const isSmallScreen = useMediaQuery({ maxWidth: 576 });
+
const [expand, setExpand] = React.useState<boolean>(false);
const collapse = (): void => setExpand(false);
const toggleExpand = (): void => setExpand(!expand);
- return (
- <Navbar
- bg="primary"
- variant="dark"
- expand="md"
- fixed="top"
- expanded={expand}
+ const createLink = (
+ link: string,
+ label: React.ReactNode,
+ className?: string
+ ): React.ReactNode => (
+ <NavLink
+ to={link}
+ activeClassName="active"
+ onClick={collapse}
+ className={className}
>
- <LinkContainer to="/" onClick={collapse}>
- <Navbar.Brand className="d-flex align-items-center">
- <TimelineLogo style={{ height: "1em" }} />
- Timeline
- </Navbar.Brand>
- </LinkContainer>
+ {label}
+ </NavLink>
+ );
+
+ return (
+ <nav className={classnames("app-bar", isSmallScreen && "small-screen")}>
+ <Link to="/" className="app-bar-brand active">
+ <TimelineLogo className="app-bar-brand-icon" />
+ Timeline
+ </Link>
- <Navbar.Toggle onClick={toggleExpand} />
+ {isSmallScreen && (
+ <i className="bi-list app-bar-toggler" onClick={toggleExpand} />
+ )}
- <Navbar.Collapse>
- <Nav className="me-auto">
- <NavLink
- to="/settings"
- className="nav-link"
- activeClassName="active"
- onClick={collapse}
- >
- {t("nav.settings")}
- </NavLink>
- <NavLink
- to="/about"
- className="nav-link"
- activeClassName="active"
- onClick={collapse}
- >
- {t("nav.about")}
- </NavLink>
+ <div
+ className={classnames(
+ "app-bar-main-area",
+ !expand && "app-bar-collapse"
+ )}
+ >
+ <div className="app-bar-link-area">
+ {createLink("/settings", t("nav.settings"))}
+ {createLink("/about", t("nav.about"))}
+ {hasAdministrationPermission &&
+ createLink("/admin", t("nav.administration"))}
+ </div>
- {hasAdministrationPermission && (
- <NavLink
- to="/admin"
- className="nav-link"
- activeClassName="active"
- onClick={collapse}
- >
- {t("nav.administration")}
- </NavLink>
- )}
- </Nav>
- <Nav className="ms-auto md-me-2">
- {user != null ? (
- <LinkContainer to="/">
- <UserAvatar
- username={user.username}
- className="avatar small rounded-circle bg-white cursor-pointer ms-auto"
- />
- </LinkContainer>
- ) : (
- <NavLink
- to="/login"
- className="nav-link"
- activeClassName="active"
- onClick={collapse}
- >
- {t("nav.login")}
- </NavLink>
- )}
- </Nav>
- </Navbar.Collapse>
- </Navbar>
+ <div className="app-bar-user-area">
+ {user != null
+ ? createLink(
+ "/",
+ <UserAvatar
+ username={user.username}
+ className="avatar small rounded-circle bg-white cursor-pointer ml-auto"
+ />,
+ "app-bar-avatar"
+ )
+ : createLink("/login", t("nav.login"))}
+ </div>
+ </div>
+ </nav>
);
};
diff --git a/FrontEnd/src/app/views/common/common.sass b/FrontEnd/src/app/views/common/common.sass
index f3022d19..991a59be 100644
--- a/FrontEnd/src/app/views/common/common.sass
+++ b/FrontEnd/src/app/views/common/common.sass
@@ -32,6 +32,90 @@
background: white
touch-action: none
+.app-bar
+ display: flex
+ align-items: center
+ height: 56px
+
+ position: fixed
+ z-index: 1030
+ top: 0
+ left: 0
+ right: 0
+
+ background-color: var(--tl-primary-color)
+
+ a
+ color: var(--tl-text-inactive-on-primary-color)
+ text-decoration: none
+ margin: 0 1em
+
+ &.active
+ color: var(--tl-text-on-primary-color)
+
+.app-bar-brand
+ display: flex
+ align-items: center
+
+.app-bar-brand-icon
+ height: 2em
+
+.app-bar-main-area
+ display: flex
+ flex-grow: 1
+
+.app-bar-link-area
+ display: flex
+ align-items: center
+ flex-shrink: 0
+
+.app-bar-user-area
+ display: flex
+ align-items: center
+ flex-shrink: 0
+ margin-left: auto
+
+.small-screen
+ .app-bar-main-area
+ position: absolute
+ top: 56px
+ left: 0
+ right: 0
+
+ transform-origin: top
+ transition: transform 0.6s
+
+ background-color: var(--tl-primary-color)
+
+ flex-direction: column
+
+ &.app-bar-collapse
+ transform: scale(1,0)
+
+ a
+ text-align: left
+ padding: 0.5em 0.5em
+
+ .app-bar-link-area
+ flex-direction: column
+ align-items: stretch
+
+ .app-bar-user-area
+ flex-direction: column
+ align-items: stretch
+ margin-left: unset
+
+ .app-bar-avatar
+ align-self: flex-end
+
+.app-bar-toggler
+ margin-left: auto
+ font-size: 2em
+ margin-right: 1em
+ color: var(--tl-text-on-primary-color)
+ cursor: pointer
+ user-select: none
+
.cru-skeleton
padding: 0 1em