diff --git a/src/index.tsx b/src/index.tsx
index beba40a..bbcda4d 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -4,6 +4,8 @@ import './index.css';
import reportWebVitals from './reportWebVitals';
import {Canvas} from "./index/Canvas";
import {Nav} from "./nav/Nav";
+import {RouterProvider} from "./router/RouterContext";
+import {Route} from "./router/Route";
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
@@ -11,8 +13,12 @@ const root = ReactDOM.createRoot(
root.render(
-
-
+
+
+
+
+
+
);
diff --git a/src/nav/Nav.tsx b/src/nav/Nav.tsx
index 425dd7a..407dbe9 100644
--- a/src/nav/Nav.tsx
+++ b/src/nav/Nav.tsx
@@ -5,6 +5,7 @@ import {Menu} from "./Menu";
import wave from "../img/menu-wave.svg";
import "./nav.scss";
import {motion} from "framer-motion";
+import {Link} from "../router/Link";
export function Nav() {
const [active, setActive] = useState(false);
@@ -35,8 +36,8 @@ function MenuButton(props : { active: boolean, setActive: (_:boolean) => void })
function Title() {
return (
-
+
Tymur Arsentiev
-
+
);
}
\ No newline at end of file
diff --git a/src/router/Link.tsx b/src/router/Link.tsx
new file mode 100644
index 0000000..6bcbc57
--- /dev/null
+++ b/src/router/Link.tsx
@@ -0,0 +1,18 @@
+import React, {PropsWithChildren} from "react";
+import {useRouter} from "./RouterContext";
+
+export function Link(props: {className: string, href: string, replace?: boolean } & PropsWithChildren) {
+ const {children, className, href, replace} = props;
+ const router = useRouter();
+
+ function onClick(event: React.MouseEvent) {
+ event.preventDefault();
+ if(replace) {
+ router.replacePage(props.href);
+ } else {
+ router.pushPage(props.href);
+ }
+ }
+
+ return {children}
+}
\ No newline at end of file
diff --git a/src/router/Route.tsx b/src/router/Route.tsx
new file mode 100644
index 0000000..e537e74
--- /dev/null
+++ b/src/router/Route.tsx
@@ -0,0 +1,12 @@
+import {PropsWithChildren} from "react";
+import {useRouter} from "./RouterContext";
+import {Path} from "./router";
+
+export function Route(props: PropsWithChildren & {path: Path}) {
+ const {path, children} = props;
+ const router = useRouter();
+
+ return <>
+ { router.current?.currentPage === path && children}
+ >
+}
\ No newline at end of file
diff --git a/src/router/RouterContext.tsx b/src/router/RouterContext.tsx
index fea1d12..6e70fbf 100644
--- a/src/router/RouterContext.tsx
+++ b/src/router/RouterContext.tsx
@@ -1,14 +1,63 @@
-import {createContext, PropsWithChildren, useContext, useSyncExternalStore} from "react";
+import {createContext, PropsWithChildren, useContext, useEffect, useSyncExternalStore} from "react";
+import {HistoryState, Path, Router} from "./router";
+import * as repl from "node:repl";
-const RouterContext = createContext<{}>({});
+const DEFAULT : Router = {
+ current: {
+ currentPage: window.location.pathname as Path
+ },
+ pushPage: function(){},
+ replacePage: function(){}
+};
+
+const RouterContext = createContext(DEFAULT);
export function useRouter() {
return useContext(RouterContext);
}
-export function RouterProvider(props : PropsWithChildren) {
+function subscribe(onChange: () => void) {
+ window.addEventListener("popstate", onChange);
- return
+ // return unsubscribe function
+ return function() {
+ window.removeEventListener("popstate", onChange);
+ }
+}
+
+function getSnapshot(): HistoryState {
+ return window.history.state ?? DEFAULT;
+}
+
+function pushState(path: string) {
+ window.history.pushState({
+ currentPage: path as Path
+ },
+ "",
+ path);
+}
+
+function replaceState(path: string) {
+ window.history.replaceState({
+ currentPage: path as Path
+ },
+ "",
+ path);
+}
+
+export function RouterProvider(props : PropsWithChildren) {
+ const state = useSyncExternalStore(subscribe, getSnapshot);
+
+ // start history with initial page
+ useEffect(() => {
+ replaceState(window.location.pathname);
+ }, []);
+
+ return
{props.children}
}
\ No newline at end of file
diff --git a/src/router/router.ts b/src/router/router.ts
new file mode 100644
index 0000000..24ae0d8
--- /dev/null
+++ b/src/router/router.ts
@@ -0,0 +1,10 @@
+export type Router = {
+ replacePage: (path: string) => void;
+ pushPage: (path: string) => void;
+ current: HistoryState
+}
+
+export type Path = `/${string}`;
+export type HistoryState = {
+ currentPage: Path
+};