(FEAT): Navbar implemented!
This commit is contained in:
parent
a0d4f29527
commit
8655df8f6b
@ -24,6 +24,7 @@
|
||||
templ
|
||||
tailwindcss_4
|
||||
tailwindcss-language-server
|
||||
tailwindcss-language-server:
|
||||
watchman
|
||||
docker-language-server
|
||||
dockerfile-language-server-nodejs
|
||||
|
||||
685
web/package-lock.json
generated
685
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -10,11 +10,13 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.16",
|
||||
"eslint-plugin-react-dom": "^2.2.4",
|
||||
"eslint-plugin-react-x": "^2.2.4",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-router-dom": "^7.9.5"
|
||||
"react-router-dom": "^7.9.5",
|
||||
"tailwindcss": "^4.1.16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.36.0",
|
||||
|
||||
@ -3,19 +3,24 @@ import Home from './pages/Home';
|
||||
import WebLayout from "./layouts/WebLayout";
|
||||
import NotFound from './pages/NotFound';
|
||||
|
||||
import ROUTE_CONSTANTS from './types/routes';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<Navigate to="/web" replace />} />
|
||||
<Route path="/web" element={<WebLayout />}>
|
||||
<Route index element={<Home />} />
|
||||
<Route path="/" element={<Navigate to={ROUTE_CONSTANTS.Home} replace />} />
|
||||
<Route path="/v2/web" element={<WebLayout />}>
|
||||
<Route index element={<Navigate to={ROUTE_CONSTANTS.Home} replace />} />
|
||||
<Route path="home" element={<Home />} />
|
||||
{/* <Route path="recipe/:id" element={<Home />} /> */}
|
||||
|
||||
</Route>
|
||||
|
||||
{/* 404: Not Found */}
|
||||
<Route path="*" element={<WebLayout />}>
|
||||
<Route path="*" element={<NotFound />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
@ -0,0 +1,116 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import ROUTE_CONSTANTS from "../types/routes.ts";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import ShoppingListIcon from "./icons/ShoppingListIcon.tsx";
|
||||
|
||||
export default function Navigation() {
|
||||
const [displayHamburgerMenu, setDisplayHamburgerMenu] = useState<boolean>(false);
|
||||
|
||||
const location = useLocation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<nav className="block md:fixed w-full z-10">
|
||||
<div
|
||||
className="relative w-full px-8 md:px-44 p-4 border-b border-gray-300 shadow-sm shadow-gray-300 bg-white flex justify-between items-center"
|
||||
>
|
||||
<div>
|
||||
<a href={ROUTE_CONSTANTS.Home}>
|
||||
<p className="select-none">Potion</p>
|
||||
</a>
|
||||
</div>
|
||||
<div className="hidden md:flex lg:flex items-center gap-8 select-none">
|
||||
<NavigationLink name="Home" url={ROUTE_CONSTANTS.Home} current={location.pathname === ROUTE_CONSTANTS.Home} />
|
||||
<NavigationLink name="Favorites" url={ROUTE_CONSTANTS.Favorites} current={location.pathname === ROUTE_CONSTANTS.Favorites} />
|
||||
<NavigationLink name="Create" url={ROUTE_CONSTANTS.Create} current={location.pathname === ROUTE_CONSTANTS.Create} />
|
||||
<NavigationLink name="Profile" url={ROUTE_CONSTANTS.Profile} current={location.pathname === ROUTE_CONSTANTS.Profile} />
|
||||
<IconNavigationLink icon={<ShoppingListIcon current={location.pathname === ROUTE_CONSTANTS.ShoppingList} />} url={ROUTE_CONSTANTS.ShoppingList} />
|
||||
</div>
|
||||
<div className="md:hidden grid place-content-center">
|
||||
<button onClick={() => setDisplayHamburgerMenu(!displayHamburgerMenu)} className="p-2">
|
||||
<svg
|
||||
className={`${displayHamburgerMenu ? "flex" : "hidden"} size-5`}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 320 512"
|
||||
>
|
||||
<path
|
||||
d="M182.6 137.4c-12.5-12.5-32.8-12.5-45.3 0l-128 128c-9.2 9.2-11.9 22.9-6.9 34.9s16.6 19.8 29.6 19.8l256 0c12.9 0 24.6-7.8 29.6-19.8s2.2-25.7-6.9-34.9l-128-128z"
|
||||
></path>
|
||||
</svg>
|
||||
<svg
|
||||
className={`${displayHamburgerMenu ? "hidden" : "flex"} size-5`}
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M0 96C0 78.3 14.3 64 32 64l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 128C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 288c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32L32 448c-17.7 0-32-14.3-32-32s14.3-32 32-32l384 0c17.7 0 32 14.3 32 32z"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<HamburgerMenu show={displayHamburgerMenu} />
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
</>
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
interface HamburgerMenuProps {
|
||||
show: boolean;
|
||||
};
|
||||
|
||||
function HamburgerMenu({ show }: HamburgerMenuProps) {
|
||||
return (
|
||||
<div className={`${show ? "flex" : "hidden"} w-full flex-col items-center absolute top-[100%] left-0 py-2 bg-white border-b border-gray-300 shadow-sm shadow-gray-300 z-20`}>
|
||||
<DropdownLink name="Home" url={ROUTE_CONSTANTS.Home} />
|
||||
<DropdownLink name="Favorites" url={ROUTE_CONSTANTS.Favorites} />
|
||||
<DropdownLink name="Create" url={ROUTE_CONSTANTS.Create} />
|
||||
<DropdownLink name="Profile" url={ROUTE_CONSTANTS.Profile} />
|
||||
<DropdownLink name="Shopping List" url={ROUTE_CONSTANTS.ShoppingList} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface DropdownLinkProps {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
function DropdownLink({ name, url }: DropdownLinkProps) {
|
||||
return (
|
||||
<a className="py-2" href={url}>
|
||||
{name}
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
interface NavigationLinkProps {
|
||||
name: string;
|
||||
url: string;
|
||||
current: boolean;
|
||||
}
|
||||
|
||||
function NavigationLink({ name, url, current }: NavigationLinkProps) {
|
||||
return (
|
||||
<a href={url} className={`${current ? "border-blue-500" : "hover:border-blue-400 border-white"} duration-150 text-gray-700 border-b-2 px-1 cursor-pointer`}>
|
||||
{name}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
interface IconNavigationLinkProps {
|
||||
icon: React.ReactElement;
|
||||
url: string;
|
||||
}
|
||||
|
||||
function IconNavigationLink({ icon, url }: IconNavigationLinkProps) {
|
||||
return (
|
||||
<a href={url} className="px-1 cursor-pointer">
|
||||
{icon}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
19
web/src/components/icons/ShoppingListIcon.tsx
Normal file
19
web/src/components/icons/ShoppingListIcon.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
interface ShoppingListIconProps {
|
||||
current: boolean;
|
||||
};
|
||||
|
||||
export default function ShoppingListIcon({ current }: ShoppingListIconProps) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 576 512"
|
||||
className={`${current ? "text-blue-500" : "text-gray-700 hover:text-blue-400"} duration-150 h-4`}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M0 24C0 10.7 10.7 0 24 0L69.5 0c22 0 41.5 12.8 50.6 32l411 0c26.3 0 45.5 25 38.6 50.4l-41 152.3c-8.5 31.4-37 53.3-69.5 53.3l-288.5 0 5.4 28.5c2.2 11.3 12.1 19.5 23.6 19.5L488 336c13.3 0 24 10.7 24 24s-10.7 24-24 24l-288.3 0c-34.6 0-64.3-24.6-70.7-58.5L77.4 54.5c-.7-3.8-4-6.5-7.9-6.5L24 48C10.7 48 0 37.3 0 24zM128 464a48 48 0 1 1 96 0 48 48 0 1 1 -96 0zm336-48a48 48 0 1 1 0 96 48 48 0 1 1 0-96z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
@import "tailwindcss";
|
||||
@ -1,11 +1,12 @@
|
||||
import { Outlet } from "react-router-dom";
|
||||
import Navigation from "../components/Navigation";
|
||||
|
||||
|
||||
export default function WebLayout() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<p> LAYOUT </p>
|
||||
<Navigation />
|
||||
<Outlet />
|
||||
</>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<p>Hello world </p>
|
||||
<p className="text-red-500">Hello world </p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
18
web/src/types/routes.ts
Normal file
18
web/src/types/routes.ts
Normal file
@ -0,0 +1,18 @@
|
||||
const VERSION_FLAG = "/v2";
|
||||
|
||||
const ROUTE_CONSTANTS: {
|
||||
Home: string;
|
||||
Favorites: string;
|
||||
Create: string;
|
||||
Profile: string;
|
||||
ShoppingList: string;
|
||||
} = {
|
||||
Home: `${VERSION_FLAG}/web/home`,
|
||||
Favorites: `${VERSION_FLAG}/web/favorites`,
|
||||
Create: `${VERSION_FLAG}/web/create`,
|
||||
Profile: `${VERSION_FLAG}/web/profile`,
|
||||
ShoppingList: `${VERSION_FLAG}/web/list`,
|
||||
|
||||
};
|
||||
|
||||
export default ROUTE_CONSTANTS;
|
||||
8
web/tailwind.config.js
Normal file
8
web/tailwind.config.js
Normal file
@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{js,ts,jsx,tsx}"
|
||||
],
|
||||
theme: { extend: {}, },
|
||||
plugins: [],
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react-swc'
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react-swc';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
plugins: [react(), tailwindcss()],
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user