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

Add Routing and Sidebar #25

Merged
merged 6 commits into from
Jan 23, 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
3 changes: 2 additions & 1 deletion frontend/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"printWidth": 100
"printWidth": 100,
"plugins": ["prettier-plugin-tailwindcss"]
}
2,346 changes: 802 additions & 1,544 deletions frontend/package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@radix-ui/react-slot": "^1.0.2",
"@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "^14.1.2",
"autoprefixer": "^10.4.16",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"date-fns": "^3.2.0",
Expand All @@ -28,6 +29,7 @@
"react": "^18",
"react-day-picker": "^8.10.0",
"react-dom": "^18",
"tailwindcss": "^3.4.1",
"react-hook-form": "^7.49.3",
"tailwind-merge": "^2.2.0",
"tailwindcss-animate": "^1.0.7",
Expand All @@ -47,6 +49,7 @@
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"husky": "^8.0.3",
"prettier-plugin-tailwindcss": "^0.5.11",
"postcss": "^8.4.33",
"prettier": "^3.1.1",
"tailwindcss": "^3.4.1",
Expand Down
Binary file added frontend/public/sidebar/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions frontend/public/sidebar/nav_menu.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file removed frontend/src/components/.keep
Empty file.
8 changes: 4 additions & 4 deletions frontend/src/components/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,22 @@ type CheckboxProps = {

export function Checkbox({ options, className, name, register }: CheckboxProps) {
return (
<div className={cn("grid gap-x-5 gap-y-3 sm:grid-cols-2 sm:min-w-2/5 min-w-4/5", className)}>
<div className={cn("sm:min-w-2/5 min-w-4/5 grid gap-x-5 gap-y-3 sm:grid-cols-2", className)}>
{options.map((item, index) => {
return item === "Other" ? (
<OtherCheckbox register={register} key={item + index} />
) : (
<div className="flex justify-between content-center " key={item + index}>
<div className="flex content-center justify-between " key={item + index}>
<label
className="justify-left grid flex-1 content-center select-none py-[15px] hover:cursor-pointer"
className="justify-left grid flex-1 select-none content-center py-[15px] hover:cursor-pointer"
htmlFor={item + index}
>
{item}
</label>
<input
{...register(name)}
id={item + index}
className="checked:bg-pia_dark_green h-[40px] self-center w-[40px] appearance-none rounded-[10px] bg-[#D9D9D9] hover:cursor-pointer"
className="h-[40px] w-[40px] appearance-none self-center rounded-[10px] bg-[#D9D9D9] checked:bg-pia_dark_green hover:cursor-pointer"
type="checkbox"
name={name}
value={item}
Expand Down
149 changes: 149 additions & 0 deletions frontend/src/components/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/**
* Navigation Component
*
* Wraps the content of the current page with the navbar
* Uses the constant in `src/constants` to populate the actual sidebar
*/
import { Poppins } from "next/font/google";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import React, { useEffect, useMemo } from "react";

import { navigation } from "../constants/navigation";
import { useWindowSize } from "../hooks/useWindowSize";
import { cn } from "../lib/utils";

const poppins = Poppins({ subsets: ["latin"], weight: "400" });

type LinkProps = {
setShelf: React.Dispatch<React.SetStateAction<boolean>>;
isMobile: boolean;
};

// the logo and company name component
const Logo = ({ setShelf, isMobile, black }: LinkProps & { black?: boolean }) => {
return (
<Link
href="/"
onClick={() => {
if (isMobile) setShelf(false);
}}
className="flex items-center gap-2 pl-8 pr-8 max-sm:w-fit max-sm:justify-normal sm:max-lg:p-0"
>
<Image
alt="company logo"
src="/sidebar/logo.png"
width={36}
height={36}
className="max-sm:w-6"
/>
<h1
className="font-[alternate-gothic] text-2xl text-white max-lg:text-lg"
style={black ? { color: "black" } : {}}
>
PLANT IT AGAIN
</h1>
</Link>
);
};

// the mapping of elements within navigation
const Links = ({ setShelf, isMobile }: LinkProps) => {
const router = useRouter();

return navigation.map((item, i) => {
return (
<Link
href={item.href}
onClick={() => {
if (isMobile) setShelf(false);
}}
className="relative flex h-10 items-center gap-4 fill-pia_accent_green pl-8 pr-8 max-sm:gap-2 sm:max-lg:p-0"
key={i}
style={router.pathname === item.href ? { fill: "white" } : {}}
>
<div className="h-4 w-4 sm:h-6 sm:w-6">{item.icon}</div>
<div
className="font-bold max-sm:text-sm sm:max-lg:hidden"
style={router.pathname === item.href ? { color: "white" } : {}}
>
{item.title}
</div>
</Link>
);
});
};

// Navigation component that wraps the content of the page
function Navigation({ children }: { children: React.ReactNode }) {
const router = useRouter();
const [offset, setOffset] = React.useState(0);
const [shelf, setShelf] = React.useState(false); // on mobile whether the navbar is open
const { width } = useWindowSize();
const isMobile = useMemo(() => width <= 640, [width]);

useEffect(() => {
const ordering = navigation.map((item) => item.href);
const idx = ordering.indexOf(router.pathname) | 0;
setOffset(idx * 68);
}, [router.pathname]);

return (
<main
className={cn(
"flex h-screen w-full bg-pia_primary_light_green max-sm:relative sm:max-lg:flex-col",
poppins.className,
)}
>
{/* mobile top bar - is not visible in nonmobile viewports */}
<div className="border-neutralGray absolute z-10 flex h-10 w-full items-center border-[1px] border-solid pl-4 sm:hidden">
<Image
src="/sidebar/nav_menu.svg"
alt="nav burger"
onClick={() => {
setShelf(true);
}}
className="w-6 sm:hidden"
width={24}
height={24}
/>
<div className="m-auto translate-x-[-20px]">
<Logo setShelf={setShelf} isMobile={isMobile} black />
</div>
</div>

{/* navbar */}
<nav
className={cn(
"z-10 flex h-full w-[240px] flex-col gap-12 bg-pia_dark_green pt-16 text-pia_accent_green transition-transform",
"max-sm:gap-8 max-sm:pt-5 sm:max-lg:h-10 sm:max-lg:w-full sm:max-lg:flex-row sm:max-lg:justify-between sm:max-lg:pl-12 sm:max-lg:pr-12 sm:max-lg:pt-0",
shelf ? "" : "max-sm:-translate-x-full",
)}
>
<Logo setShelf={setShelf} isMobile={isMobile} />
<div className="relative flex flex-col gap-7 max-sm:gap-2 sm:max-lg:flex-row">
<div
className="absolute h-10 w-2 rounded-br-lg rounded-tr-lg bg-[white] max-lg:hidden"
style={{ top: offset, transition: "0.2s all" }}
></div>
<Links setShelf={setShelf} isMobile={isMobile} />
</div>
</nav>

<div
className="h-full w-full p-[24px] max-lg:absolute max-lg:pt-14 lg:w-[calc(100%-240px)]"
onClick={(e) => {
if (isMobile) {
e.stopPropagation();
setShelf(false);
}
}}
>
{children}
</div>
</main>
);
}

export default Navigation;
6 changes: 3 additions & 3 deletions frontend/src/components/OtherCheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ export default function OtherCheckbox({ register }: OtherCheckboxProps) {
placeholder="Type Here..."
/>
) : (
<div className="flex justify-between content-center ">
<div className="flex content-center justify-between ">
<label
className="justify-left grid flex-1 content-center select-none py-[15px] hover:cursor-pointer"
className="justify-left grid flex-1 select-none content-center py-[15px] hover:cursor-pointer"
htmlFor={"Othercheckbox"}
>
{"Other"}
</label>
<input
id={"Othercheckbox"}
className="checked:bg-pia_dark_green h-[40px] self-center w-[40px] appearance-none rounded-[10px] bg-[#D9D9D9] hover:cursor-pointer"
className="h-[40px] w-[40px] appearance-none self-center rounded-[10px] bg-[#D9D9D9] checked:bg-pia_dark_green hover:cursor-pointer"
type="checkbox"
onChange={() => {
setChecked(true);
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/Radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ export default function Radio({ options, register, name, className }: RadioProps
<div className="flex items-center" key={option + index}>
<input
{...register(name)}
className="w-5 h-5 accent-pia_dark_green hover:cursor-pointer"
className="h-5 w-5 accent-pia_dark_green hover:cursor-pointer"
id={option + index}
type="radio"
value={option}
/>
<label
className="select-none pl-5 flex-1 hover:cursor-pointer"
className="flex-1 select-none pl-5 hover:cursor-pointer"
htmlFor={option + index}
>
{option}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/Textfield.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,21 @@ export function Textfield({
<Popover>
<div
className={cn(
"border-pia_border focus-within:border-pia_dark_green relative flex rounded-md border-[1px] px-2 py-3 ",
"relative flex rounded-md border-[1px] border-pia_border px-2 py-3 focus-within:border-pia_dark_green ",
className,
)}
>
<input
{...register(name)}
className="appearance-none placeholder-pia_accent focus-visible:out px-2 outline-none w-full bg-inherit"
className="focus-visible:out w-full appearance-none bg-inherit px-2 placeholder-pia_accent outline-none"
id={label + placeholder}
type={type}
placeholder={placeholder}
/>

{label ? (
<label
className="text-pia_border-200 absolute left-[1em] top-[-1em] bg-[white] p-[3px] text-xs select-none"
className="absolute left-[1em] top-[-1em] select-none bg-[white] p-[3px] text-xs text-pia_border-200"
htmlFor={label + placeholder}
>
{label}
Expand Down
108 changes: 108 additions & 0 deletions frontend/src/constants/navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* The array that populates the navbar
*/

type NavigationEntry = {
title: string;
href: string;
icon: React.ReactNode;
};

export const navigation: NavigationEntry[] = [
{
title: "Home",
href: "/",
icon: (
<svg
width="100%"
height="100%"
viewBox="0 0 24 24"
fill="inherit"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M21.743 12.331L12.743 2.33103C12.364 1.90903 11.636 1.90903 11.257 2.33103L2.25698 12.331C2.12744 12.4746 2.04241 12.6528 2.01223 12.8438C1.98205 13.0348 2.00802 13.2305 2.08698 13.407C2.24698 13.768 2.60498 14 2.99998 14H4.99998V21C4.99998 21.2652 5.10534 21.5196 5.29288 21.7071C5.48041 21.8947 5.73477 22 5.99998 22H8.99998C9.2652 22 9.51955 21.8947 9.70709 21.7071C9.89463 21.5196 9.99998 21.2652 9.99998 21V17H14V21C14 21.2652 14.1053 21.5196 14.2929 21.7071C14.4804 21.8947 14.7348 22 15 22H18C18.2652 22 18.5196 21.8947 18.7071 21.7071C18.8946 21.5196 19 21.2652 19 21V14H21C21.1937 14.0009 21.3834 13.9453 21.546 13.8402C21.7087 13.735 21.8372 13.5848 21.916 13.4079C21.9947 13.231 22.0203 13.035 21.9896 12.8438C21.9589 12.6525 21.8732 12.4744 21.743 12.331Z"
fill="inherit"
/>
</svg>
),
},
{
title: "Programs",
href: "/programs",
icon: (
<svg
width="100%"
height="100%"
viewBox="0 0 24 24"
fill="inherit"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.55 22C8.08333 22 7.675 21.8583 7.325 21.575C6.975 21.2917 6.74167 20.925 6.625 20.475L5.5 16H18.5L17.375 20.475C17.2583 20.925 17.025 21.2917 16.675 21.575C16.325 21.8583 15.9167 22 15.45 22H8.55ZM12 8.00001C12 6.50001 12.5083 5.20001 13.525 4.10001C14.5417 3.00001 15.8083 2.33334 17.325 2.10001C17.4083 2.08334 17.4833 2.09167 17.55 2.12501C17.6167 2.15834 17.6833 2.20001 17.75 2.25001C17.8167 2.30001 17.8627 2.36234 17.888 2.43701C17.9133 2.51167 17.9173 2.59101 17.9 2.67501C17.7167 3.99167 17.1793 5.13734 16.288 6.11201C15.3967 7.08667 14.3007 7.68267 13 7.90001V10H20C20.2833 10 20.521 10.096 20.713 10.288C20.905 10.48 21.0007 10.7173 21 11V13C21 13.55 20.8043 14.021 20.413 14.413C20.0217 14.805 19.5507 15.0007 19 15H5C4.45 15 3.97933 14.8043 3.588 14.413C3.19667 14.0217 3.00067 13.5507 3 13V11C3 10.7167 3.096 10.4793 3.288 10.288C3.48 10.0967 3.71733 10.0007 4 10H11V7.90001C9.7 7.68334 8.60433 7.08767 7.713 6.11301C6.82167 5.13834 6.284 3.99234 6.1 2.67501C6.08333 2.59167 6.08767 2.51267 6.113 2.43801C6.13833 2.36334 6.184 2.30067 6.25 2.25001C6.31667 2.20001 6.38333 2.15834 6.45 2.12501C6.51667 2.09167 6.59167 2.08334 6.675 2.10001C8.19167 2.33334 9.45833 3.00001 10.475 4.10001C11.4917 5.20001 12 6.50001 12 8.00001Z"
fill="inherit"
/>
</svg>
),
},
{
title: "Profile",
href: "/profile",
icon: (
<svg
width="100%"
height="100%"
viewBox="0 0 24 24"
fill="inherit"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8 7C8 5.93913 8.42143 4.92172 9.17157 4.17157C9.92172 3.42143 10.9391 3 12 3C13.0609 3 14.0783 3.42143 14.8284 4.17157C15.5786 4.92172 16 5.93913 16 7C16 8.06087 15.5786 9.07828 14.8284 9.82843C14.0783 10.5786 13.0609 11 12 11C10.9391 11 9.92172 10.5786 9.17157 9.82843C8.42143 9.07828 8 8.06087 8 7ZM8 13C6.67392 13 5.40215 13.5268 4.46447 14.4645C3.52678 15.4021 3 16.6739 3 18C3 18.7956 3.31607 19.5587 3.87868 20.1213C4.44129 20.6839 5.20435 21 6 21H18C18.7956 21 19.5587 20.6839 20.1213 20.1213C20.6839 19.5587 21 18.7956 21 18C21 16.6739 20.4732 15.4021 19.5355 14.4645C18.5979 13.5268 17.3261 13 16 13H8Z"
fill="inherit"
/>
</svg>
),
},
{
title: "Notifications",
href: "/notifications",
icon: (
<svg
xmlns="http://www.w3.org/2000/svg"
width="100%"
height="100%"
viewBox="0 0 24 24"
fill="inherit"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M13 3C13 2.44772 12.5523 2 12 2C11.4477 2 11 2.44772 11 3V4.08296C8.16229 4.55904 6 7.027 6 10V14.6972L4.16795 17.4453C3.96338 17.7522 3.94431 18.1467 4.11833 18.4719C4.29235 18.797 4.63121 19 5 19H19C19.3688 19 19.7077 18.797 19.8817 18.4719C20.0557 18.1467 20.0366 17.7522 19.8321 17.4453L18 14.6972V10C18 7.027 15.8377 4.55904 13 4.08296V3ZM12 6C9.79086 6 8 7.79086 8 10V15C8 15.1974 7.94156 15.3904 7.83205 15.5547L6.86852 17H17.1315L16.168 15.5547C16.0584 15.3904 16 15.1974 16 15V10C16 7.79086 14.2091 6 12 6Z"
fill="inherit"
/>
<path
d="M12 22C13.1046 22 14 21.1046 14 20H10C10 21.1046 10.8954 22 12 22Z"
fill="inherit"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M13 3C13 2.44772 12.5523 2 12 2C11.4477 2 11 2.44772 11 3V4.08296C8.16229 4.55904 6 7.027 6 10V14.6972L4.16795 17.4453C3.96338 17.7522 3.94431 18.1467 4.11833 18.4719C4.29235 18.797 4.63121 19 5 19H19C19.3688 19 19.7077 18.797 19.8817 18.4719C20.0557 18.1467 20.0366 17.7522 19.8321 17.4453L18 14.6972V10C18 7.027 15.8377 4.55904 13 4.08296V3ZM12 6C9.79086 6 8 7.79086 8 10V15C8 15.1974 7.94156 15.3904 7.83205 15.5547L6.86852 17H17.1315L16.168 15.5547C16.0584 15.3904 16 15.1974 16 15V10C16 7.79086 14.2091 6 12 6Z"
stroke="inherit"
stroke-width="0.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M12 22C13.1046 22 14 21.1046 14 20H10C10 21.1046 10.8954 22 12 22Z"
stroke="inherit"
stroke-width="0.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
),
},
];
Loading