diff --git a/frontend/components/common/Avatar.tsx b/frontend/components/common/Avatar.tsx
index 3cedd6182..3dd9a81b5 100644
--- a/frontend/components/common/Avatar.tsx
+++ b/frontend/components/common/Avatar.tsx
@@ -12,10 +12,10 @@ const S_Container = styled("div", {
position: "relative",
userSelect: "none",
overflow: "hidden",
- width: "38px",
- minWidth: "38px",
- height: "38px",
- borderRadius: "16px",
+ width: "var(--item-size)",
+ minWidth: "var(--item-size)",
+ height: "var(--item-size)",
+ borderRadius: "$rounded",
});
const S_Avatar = styled("img", {
diff --git a/frontend/components/layout/HamburgerButton.tsx b/frontend/components/layout/HamburgerButton.tsx
new file mode 100644
index 000000000..f6a811606
--- /dev/null
+++ b/frontend/components/layout/HamburgerButton.tsx
@@ -0,0 +1,121 @@
+import { styled } from "stitches.config";
+
+export function HamburgerButton({
+ isExpanded,
+ onClick,
+}: {
+ onClick: () => void;
+ isExpanded: boolean;
+}) {
+ return (
+
+
+
+ );
+}
+
+const S_TransformingBurger = styled("button", {
+ display: "flex",
+ width: "var(--item-size)",
+ height: "var(--item-size)",
+ flexDirection: "column",
+ alignItems: "center",
+ justifyContent: "center",
+ padding: "$1",
+ border: "3px solid",
+ borderColor: "$bgLighter",
+ backgroundColor: "transparent",
+ borderRadius: "$rounded",
+ color: "inherit",
+ cursor: "pointer",
+ gap: "2px",
+
+ "@sm": {
+ display: "none",
+ },
+});
+
+const S_TopLine = styled("rect", {
+ transform: "none",
+ transformOrigin: "16px 10px",
+ transitionDuration: "150ms",
+ transitionProperty: "transform",
+ transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)",
+
+ variants: {
+ type: {
+ expanded: {
+ transform: "translateY(7px) rotate(45deg)",
+ },
+ },
+ },
+});
+
+const S_MiddleLine = styled("rect", {
+ opacity: 1,
+ transitionDuration: "150ms",
+ transitionProperty: "opacity",
+ transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)",
+
+ variants: {
+ type: {
+ expanded: {
+ opacity: 0,
+ },
+ },
+ },
+});
+
+const S_BottomLine = styled("rect", {
+ transform: "none",
+ transformOrigin: "16px 22px",
+ transitionDuration: "150ms",
+ transitionProperty: "transform",
+ transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)",
+
+ variants: {
+ type: {
+ expanded: {
+ transform: "translateY(-5px) rotate(-45deg)",
+ },
+ },
+ },
+});
diff --git a/frontend/components/layout.tsx b/frontend/components/layout/Layout.tsx
similarity index 66%
rename from frontend/components/layout.tsx
rename to frontend/components/layout/Layout.tsx
index bbd1019e6..e08ba2276 100644
--- a/frontend/components/layout.tsx
+++ b/frontend/components/layout/Layout.tsx
@@ -1,41 +1,36 @@
-import { ReactNode } from "react";
+import { ReactNode, useState } from "react";
import NextImage from "next/image";
-import logo from "../assets/img/logo.png";
-import { Avatar } from "./common/Avatar";
+import NextLink from "next/link";
+import logo from "assets/img/logo.png";
+import { Avatar } from "components/common/Avatar";
import { styled } from "stitches.config";
-import { SearchInput } from "./common/SearchInput";
-
-const navItems = [
- {
- title: "builds",
- items: ["browse", "gear", "analyzer"],
- },
- {
- title: "play",
- items: ["calendar", "battle", "Rankings"],
- },
- {
- title: "tools",
- items: ["planner", "rotations", "top 500"],
- },
- {
- title: "misc",
- items: ["badges", "links"],
- },
-];
+import { SearchInput } from "components/common/SearchInput";
+import { HamburgerButton } from "./HamburgerButton";
+import { navItems } from "utils/constants";
+import { MobileNav } from "./MobileNav";
export function Layout({ children }: { children: ReactNode }) {
+ const [menuExpanded, setMenuExpanded] = useState(false);
return (
<>
-
-
-
-
+
+
+
+
+
+
+
+
+ setMenuExpanded((expanded) => !expanded)}
+ />
+
{navItems.map((navItem) => (
@@ -59,10 +54,19 @@ export function Layout({ children }: { children: ReactNode }) {
}
const S_Header = styled("header", {
+ position: "relative",
display: "grid",
- gridTemplateColumns: "repeat(3, 1fr)",
+ gridTemplateColumns: "repeat(2, 1fr)",
alignItems: "center",
padding: "$4",
+ "--item-size": "3rem",
+ zIndex: 10,
+ backgroundColor: "$bg",
+
+ "@sm": {
+ gridTemplateColumns: "repeat(3, 1fr)",
+ "--item-size": "38px",
+ },
});
const S_LogoContainer = styled("div", {
@@ -73,6 +77,18 @@ const S_LogoContainer = styled("div", {
padding: "$1",
borderRadius: "$rounded",
justifySelf: "flex-start",
+ cursor: "pointer",
+ width: "var(--item-size)",
+ minWidth: "var(--item-size)",
+ height: "var(--item-size)",
+});
+
+const S_SearchContainer = styled("div", {
+ display: "none",
+
+ "@sm": {
+ display: "block",
+ },
});
const S_RightContainer = styled("div", {
@@ -82,10 +98,14 @@ const S_RightContainer = styled("div", {
});
const S_Nav = styled("nav", {
- display: "flex",
+ display: "none",
justifyContent: "center",
backgroundColor: "$bgLighter",
backgroundImage: `url(/svg/background-pattern.svg)`,
+
+ "@sm": {
+ display: "flex",
+ },
});
const S_NavItems = styled("div", {
diff --git a/frontend/components/layout/MobileNav.tsx b/frontend/components/layout/MobileNav.tsx
new file mode 100644
index 000000000..e81ef50b5
--- /dev/null
+++ b/frontend/components/layout/MobileNav.tsx
@@ -0,0 +1,113 @@
+import { SearchInput } from "components/common/SearchInput";
+import { styled } from "stitches.config";
+import { navItems } from "utils/constants";
+import NextLink from "next/link";
+import { Fragment } from "react";
+
+export function MobileNav({ isExpanded }: { isExpanded: boolean }) {
+ return (
+
+
+
+
+
+ {navItems.map((navItem) => {
+ return (
+
+ {navItem.title}
+ {navItem.items.map((item) => {
+ return (
+
+
+
+ {item}
+
+
+ );
+ })}
+
+ );
+ })}
+
+
+ );
+}
+
+const S_Container = styled("nav", {
+ position: "absolute",
+ bottom: "100vh",
+ width: "100%",
+ height: "100%",
+ transition: "bottom 0.5s",
+ transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)",
+ backgroundImage: `url(/svg/background-pattern.svg)`,
+ backgroundColor: "$bgLighter",
+ zIndex: 5,
+ overflowY: "auto",
+ paddingBottom: "$6",
+
+ "@sm": {
+ display: "none",
+ },
+
+ variants: {
+ type: {
+ expanded: {
+ bottom: "0",
+ },
+ },
+ },
+});
+
+const S_TopAction = styled("div", {
+ display: "grid",
+ gap: "$4",
+ placeItems: "center",
+ backgroundColor: "$bg",
+ paddingTop: "$24",
+ paddingBottom: "$8",
+});
+
+const S_LinksContainer = styled("div", {
+ display: "grid",
+ justifyContent: "center",
+ gridAutoColumns: "1fr",
+ gridAutoRows: "4rem",
+ paddingX: "$24",
+});
+
+const S_NavLinkImage = styled("img", {
+ width: "2.5rem",
+ marginRight: "$3",
+});
+
+const S_GroupTitle = styled("div", {
+ textTransform: "uppercase",
+ alignSelf: "flex-end",
+ justifySelf: "center",
+ paddingX: "$3",
+ paddingY: "$2",
+ marginBottom: "$1",
+ backgroundColor: "$bg",
+ fontWeight: "$bold",
+});
+
+const S_NavLink = styled("div", {
+ display: "flex",
+ alignItems: "center",
+ textTransform: "capitalize",
+ borderTop: "3px solid $bgLighter",
+ fontWeight: "$bold",
+ backgroundColor: "$bg",
+ paddingX: "$2",
+ fontSize: "$sm",
+
+ "&:last-child": {
+ borderBottom: "3px solid $bgLighter",
+ },
+});
diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx
index 4d349995e..c26891824 100644
--- a/frontend/pages/_app.tsx
+++ b/frontend/pages/_app.tsx
@@ -4,7 +4,7 @@ import "./_app.css";
import { AppProps } from "next/app";
import Head from "next/head";
import { SWRConfig } from "swr";
-import { Layout } from "../components/layout";
+import { Layout } from "components/layout/Layout";
import { globalCss } from "stitches.config";
const globalStyles = globalCss({
diff --git a/frontend/stitches.config.ts b/frontend/stitches.config.ts
index 68dd54fca..59bee7963 100644
--- a/frontend/stitches.config.ts
+++ b/frontend/stitches.config.ts
@@ -41,6 +41,7 @@ export const {
"0.5": "0.125rem",
"1": "0.25rem",
"2": "0.5rem",
+ // TODO: fix vars with . "invalid property"
"2.5": "0.625rem",
"3": "0.75rem",
"3.5": "0.875rem",
diff --git a/frontend/utils/constants.ts b/frontend/utils/constants.ts
new file mode 100644
index 000000000..f4bec3f1d
--- /dev/null
+++ b/frontend/utils/constants.ts
@@ -0,0 +1,18 @@
+export const navItems = [
+ {
+ title: "builds",
+ items: ["browse", "gear", "analyzer"],
+ },
+ {
+ title: "play",
+ items: ["calendar", "battle", "Rankings"],
+ },
+ {
+ title: "tools",
+ items: ["planner", "rotations", "top 500"],
+ },
+ {
+ title: "misc",
+ items: ["badges", "links"],
+ },
+];