aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd/src/views
diff options
context:
space:
mode:
Diffstat (limited to 'FrontEnd/src/views')
-rw-r--r--FrontEnd/src/views/common/AppBar.css53
-rw-r--r--FrontEnd/src/views/common/AppBar.tsx73
-rw-r--r--FrontEnd/src/views/common/breakpoints.ts3
-rw-r--r--FrontEnd/src/views/common/common.ts3
-rw-r--r--FrontEnd/src/views/common/hooks.ts14
-rw-r--r--FrontEnd/src/views/common/index.css9
6 files changed, 117 insertions, 38 deletions
diff --git a/FrontEnd/src/views/common/AppBar.css b/FrontEnd/src/views/common/AppBar.css
index 272a99ad..67fd9516 100644
--- a/FrontEnd/src/views/common/AppBar.css
+++ b/FrontEnd/src/views/common/AppBar.css
@@ -1,6 +1,4 @@
.app-bar {
- display: flex;
- align-items: center;
height: 56px;
position: fixed;
z-index: 1030;
@@ -8,52 +6,53 @@
left: 0;
right: 0;
background-color: var(--cru-primary-color);
- transition: background-color 1s;
}
-.app-bar .cru-avatar {
- background-color: white;
+.app-bar.desktop {
+ display: flex;
}
-.app-bar a {
- color: var(--cru-primary-on-color);
- text-decoration: none;
- margin: 0 1em;
- transition: color 1s;
+.app-bar.desktop .app-bar-brand {
+ display: flex;
+ align-items: center;
}
-.app-bar a:hover {
- color: var(--cru-primary-on-color);
+.app-bar.desktop .app-bar-brand-icon {
+ height: 2em;
}
-.app-bar a.active {
- color: var(--cru-primary-on-color);
+.app-bar.desktop .app-bar-main-area {
+ display: flex;
+ flex-grow: 1;
}
-.app-bar-brand {
+.app-bar.desktop .app-bar-link-area {
+ display: flex;
+}
+
+.app-bar.desktop a {
+ background-color: var(--cru-primary-color);
+ color: var(--cru-primary-on-color);
+ text-decoration: none;
display: flex;
align-items: center;
+ padding: 0 1em;
}
-.app-bar-brand-icon {
- height: 2em;
+.app-bar.desktop a:hover {
+ filter: brightness(var(--cru-hover-brightness));
}
-.app-bar-main-area {
- display: flex;
- flex-grow: 1;
+.app-bar.desktop a:focus {
+ filter: brightness(var(--cru-focus-brightness));
}
-.app-bar-link-area {
- display: flex;
- align-items: center;
- flex-shrink: 0;
+.app-bar.desktop a:active {
+ filter: brightness(var(--cru-press-brightness));
}
-.app-bar-user-area {
+.app-bar.desktop .app-bar-user-area {
display: flex;
- align-items: center;
- flex-shrink: 0;
margin-left: auto;
}
diff --git a/FrontEnd/src/views/common/AppBar.tsx b/FrontEnd/src/views/common/AppBar.tsx
index 444d903e..180d0db6 100644
--- a/FrontEnd/src/views/common/AppBar.tsx
+++ b/FrontEnd/src/views/common/AppBar.tsx
@@ -3,7 +3,7 @@ import classnames from "classnames";
import { Link, NavLink } from "react-router-dom";
import { useMediaQuery } from "react-responsive";
-import { useC } from "./common";
+import { I18nText, useC, useMobile } from "./common";
import { useUser } from "@/services/user";
import TimelineLogo from "./TimelineLogo";
@@ -11,7 +11,71 @@ import UserAvatar from "./user/UserAvatar";
import "./AppBar.css";
-export default function AppBar() {
+function AppBarNavLink({
+ link,
+ className,
+ label,
+ children,
+}: {
+ link: string;
+ className?: string;
+ label?: I18nText;
+ children?: React.ReactNode;
+}) {
+ if (label != null && children != null) {
+ throw new Error("AppBarNavLink: label and children cannot be both set");
+ }
+
+ const c = useC();
+
+ return (
+ <NavLink
+ to={link}
+ className={({ isActive }) => classnames(className, isActive && "active")}
+ >
+ {children != null ? children : c(label)}
+ </NavLink>
+ );
+}
+
+function DesktopAppBar() {
+ const user = useUser();
+ const hasAdministrationPermission = user && user.hasAdministrationPermission;
+
+ return (
+ <nav className="desktop app-bar">
+ <Link to="/" className="app-bar-brand active">
+ <TimelineLogo className="app-bar-brand-icon" />
+ Timeline
+ </Link>
+ <div className="app-bar-main-area">
+ <div className="app-bar-link-area">
+ <AppBarNavLink link="/settings" label="nav.settings" />
+ <AppBarNavLink link="/about" label="nav.about" />
+ {hasAdministrationPermission && (
+ <AppBarNavLink link="/admin" label="nav.administration" />
+ )}
+ </div>
+
+ <div className="app-bar-user-area">
+ {user != null ? (
+ <AppBarNavLink link="/" className="app-bar-avatar">
+ <UserAvatar
+ username={user.username}
+ className="cru-avatar small cru-round cursor-pointer ml-auto"
+ />
+ </AppBarNavLink>
+ ) : (
+ <AppBarNavLink link="/login" label="nav.login" />
+ )}
+ </div>
+ </div>
+ </nav>
+ );
+}
+
+// TODO: Go make this!
+function MobileAppBar() {
const c = useC();
const user = useUser();
@@ -77,3 +141,8 @@ export default function AppBar() {
</nav>
);
}
+
+export default function AppBar() {
+ const isMobile = useMobile();
+ return isMobile ? <MobileAppBar /> : <DesktopAppBar />;
+}
diff --git a/FrontEnd/src/views/common/breakpoints.ts b/FrontEnd/src/views/common/breakpoints.ts
new file mode 100644
index 00000000..fb281610
--- /dev/null
+++ b/FrontEnd/src/views/common/breakpoints.ts
@@ -0,0 +1,3 @@
+export const breakpoints = {
+ sm: 576,
+} as const;
diff --git a/FrontEnd/src/views/common/common.ts b/FrontEnd/src/views/common/common.ts
index e3a5a2a2..d3db9f93 100644
--- a/FrontEnd/src/views/common/common.ts
+++ b/FrontEnd/src/views/common/common.ts
@@ -10,3 +10,6 @@ export const themeColors = [
] as const;
export type ThemeColor = (typeof themeColors)[number];
+
+export { breakpoints } from "./breakpoints";
+export { useMobile } from "./hooks";
diff --git a/FrontEnd/src/views/common/hooks.ts b/FrontEnd/src/views/common/hooks.ts
new file mode 100644
index 00000000..c1fa5774
--- /dev/null
+++ b/FrontEnd/src/views/common/hooks.ts
@@ -0,0 +1,14 @@
+// TODO: Migrate hooks
+
+export {
+ useIsSmallScreen,
+ useClickOutside,
+ useScrollToBottom,
+} from "@/utilities/hooks";
+
+import { useMediaQuery } from "react-responsive";
+import { breakpoints } from "./breakpoints";
+
+export function useMobile(): boolean {
+ return useMediaQuery({ maxWidth: breakpoints.sm });
+}
diff --git a/FrontEnd/src/views/common/index.css b/FrontEnd/src/views/common/index.css
index bd556a81..f87fdfd2 100644
--- a/FrontEnd/src/views/common/index.css
+++ b/FrontEnd/src/views/common/index.css
@@ -6,21 +6,12 @@
margin-block: 0;
}
-*::before {
- box-sizing: border-box;
-}
-
-*::after {
- box-sizing: border-box;
-}
-
body {
font-family: var(--cru-default-font-family);
background: var(--cru-surface-color);
color: var(--cru-surface-on-color);
}
-
.cru-text-center {
text-align: center;
}