Browse Source

feat: replace react-router with wouter

Big wins!
pull/2/head
Muthu Kumar 12 months ago
parent
commit
1d3a61b601
Failed to extract signature
  1. 4
      package.json
  2. 9537
      pnpm-lock.yaml
  3. 5
      src/blog.tsx
  4. 47
      src/components/Container.tsx
  5. 19
      src/components/Menu.tsx
  6. 41
      src/index.tsx
  7. 17
      src/pages/blog/Home.tsx
  8. 6
      src/pages/blog/components/BlogContent.tsx
  9. 10
      src/pages/main/404.tsx
  10. 14
      src/pages/main/Contact.tsx
  11. 7
      src/util/index.ts
  12. 9
      vite.config.ts

4
package.json

@ -23,7 +23,7 @@
"marked": "^9.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.16.0"
"wouter": "^2.11.0"
},
"devDependencies": {
"@svgr/rollup": "^8.1.0",
@ -32,9 +32,7 @@
"@types/node": "^20.8.0",
"@types/react": "^18.2.24",
"@types/react-dom": "^18.2.8",
"@types/react-router-dom": "^5.3.3",
"@vitejs/plugin-react": "^4.1.0",
"react-scripts": "5.0.1",
"typescript": "^5.2.2",
"vite": "^4.4.9"
}

9537
pnpm-lock.yaml

File diff suppressed because it is too large

5
src/blog.tsx

@ -1,15 +1,12 @@
import React from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter as Router } from "react-router-dom";
import "./index.css";
import BlogHome from "./pages/blog/Home";
createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<Router>
<BlogHome />
</Router>
<BlogHome />
</React.StrictMode>,
);

47
src/components/Container.tsx

@ -1,6 +1,6 @@
import React, { useState, useEffect, useRef, useLayoutEffect } from "react";
import { css, cx } from "@emotion/css";
import { useNavigate } from "react-router-dom";
import useLocation from "wouter/use-location";
import { ReactComponent as Logo } from "../assets/logo.svg";
import { ReactComponent as Right } from "../assets/arrow-right.svg";
@ -11,20 +11,24 @@ import useMediaQuery from "../util/useMediaQuery";
const [timer, clear] = getTimeout();
const Container: React.FC<{
children: (string | React.DetailedReactHTMLElement<any, HTMLElement> | React.ReactElement)[];
children: (
| string
| React.DetailedReactHTMLElement<any, HTMLElement>
| React.ReactElement
)[];
hideNav?: boolean;
arrowReversed?: boolean;
end?: boolean;
next?: string;
className?: string;
}> = ({
children: _children,
hideNav = false,
arrowReversed = false,
end = false,
next,
className,
...props
}) => {
const navigate = useNavigate();
const [, navigate] = useLocation();
const mobile = useMediaQuery("(max-width: 50rem)");
@ -37,11 +41,20 @@ const Container: React.FC<{
const children = React.Children.map(
_children,
(child: string | React.DetailedReactHTMLElement<any, HTMLElement> | React.ReactElement) =>
(
child:
| string
| React.DetailedReactHTMLElement<any, HTMLElement>
| React.ReactElement,
) =>
!child || typeof child === "string"
? child
: React.cloneElement(child, {
style: { opacity: 0, transform: "translateY(3rem)", transition: "all 300ms" },
style: {
opacity: 0,
transform: "translateY(3rem)",
transition: "all 300ms",
},
}),
);
@ -52,14 +65,19 @@ const Container: React.FC<{
if (highlightCircle.current) {
highlightCircle.current.classList.add("highlight");
timer(
() => highlightCircle.current && highlightCircle.current.classList.remove("highlight"),
() =>
highlightCircle.current &&
highlightCircle.current.classList.remove("highlight"),
1500,
);
}
if (nextBtn.current) {
nextBtn.current.style.width = "4rem";
timer(() => nextBtn.current && (nextBtn.current.style.right = "10vw"), 300);
timer(
() => nextBtn.current && (nextBtn.current.style.right = "10vw"),
300,
);
}
if (containerChild.current) {
@ -86,7 +104,9 @@ const Container: React.FC<{
const handleResize = () => {
if (containerChild.current && logoContainer.current)
logoContainer.current.style.left = `${containerChild.current.getBoundingClientRect().x}px`;
logoContainer.current.style.left = `${
containerChild.current.getBoundingClientRect().x
}px`;
};
useEffect(() => {
@ -101,7 +121,9 @@ const Container: React.FC<{
const handleNext: React.MouseEventHandler<HTMLButtonElement> = e => {
if (containerChild.current) {
([...containerChild.current.children] as (HTMLElement | SVGElement)[]).forEach(child => {
(
[...containerChild.current.children] as (HTMLElement | SVGElement)[]
).forEach(child => {
child.style.marginBottom = "2rem";
child.style.opacity = "0";
});
@ -201,6 +223,7 @@ const Container: React.FC<{
<button
onClick={handleNext}
ref={nextBtn}
title={end ? "Back to start" : "Next page"}
className={css`
position: fixed;
right: 14vw;
@ -217,7 +240,7 @@ const Container: React.FC<{
transition: all 300ms;
overflow: hidden;
${arrowReversed ? "rotate: 180deg;" : ""}
${end ? "rotate: 180deg;" : ""}
&:hover * {
fill: var(--primary-colour);

19
src/components/Menu.tsx

@ -1,9 +1,9 @@
import React from "react";
import { Link } from "react-router-dom";
import { css, cx } from "@emotion/css";
import { motion } from "framer-motion";
import RevealChildren from "./RevealChildren";
import useMediaQuery from "../util/useMediaQuery";
import { useNav } from "../util";
const menu = [
{ name: "Home", link: "/" },
@ -57,18 +57,19 @@ const mobileMenu = css`
}
`;
const Menu: React.FC<{ show?: boolean; setShowMenu: (show: boolean) => void }> = ({
show = false,
setShowMenu,
}) => {
const Menu: React.FC<{
show?: boolean;
setShowMenu: (show: boolean) => void;
}> = ({ show = false, setShowMenu }) => {
const navigate = useNav();
// use same query as elsewhere for consistency
const mobile = useMediaQuery("(max-width: 50rem)");
const notmobile = !mobile;
const menuItems = menu.map(item => (
<Link key={item.link} to={item.link}>
{item.name}
</Link>
const menuItems = menu.map(({ link, name }) => (
<a key={link} onClick={navigate(link)} href={link}>
{name}
</a>
));
return (

41
src/index.tsx

@ -3,7 +3,7 @@ import React from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import useLocation from "wouter/use-location";
import Home from "./pages/main/Home";
import Exp from "./pages/main/Exp";
@ -13,22 +13,33 @@ import Live from "./pages/main/Live";
import NotFound from "./pages/main/404";
import BlogHome from "./pages/blog/Home";
import { BlogPost } from "./pages/blog/components/BlogContent";
createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/experience" element={<Exp />} />
<Route path="/projects" element={<Projects />} />
<Route path="/contact" element={<Contact />} />
<Route path="/live" element={<Live />} />
function App() {
const [location] = useLocation();
{/* <Route path="/blog" element={<BlogHome />} /> */}
{/* <Route path="/blog/*" element={<BlogHome />} /> */}
switch (location) {
case "/":
return <Home />;
case "/experience":
return <Exp />;
case "/projects":
return <Projects />;
case "/contact":
return <Contact />;
case "/live":
return <Live />;
case "/blog":
case "/blog/":
// return <BlogHome />;
default:
// if (location.startsWith("/blog")) return <BlogPost />;
return <NotFound />;
}
}
<Route path="/*" element={<NotFound />} />
</Routes>
</Router>
createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);

17
src/pages/blog/Home.tsx

@ -1,11 +1,12 @@
import { css, cx } from "@emotion/css";
import React, { useEffect, useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom";
import useLocation from "wouter/use-location";
import { Spacer } from "../../components/Spacer";
import { ArticleSubHeader } from "./components/ArticleSubHeader";
import { BlogPost } from "./components/BlogContent";
import { articles, getBlogPath } from "../../data";
import { ReactComponent as DrawClose } from "../../assets/arrow-thin.svg";
import { useNav } from "../../util";
const Header: React.FC = () => {
return (
@ -57,10 +58,10 @@ const Header: React.FC = () => {
};
const BlogHome: React.FC = () => {
const location = useLocation();
const navigate = useNavigate();
const [location] = useLocation();
const navigate = useNav();
const isArticleOpen = Boolean(location.pathname.split("/blog")[1]);
const isArticleOpen = Boolean(location.split("/blog")[1]);
const [isAsideClosed, setAsideClosed] = useState(isArticleOpen);
useEffect(() => {
@ -72,7 +73,7 @@ const BlogHome: React.FC = () => {
if (!isArticleOpen) return;
const handler = (e: KeyboardEvent) =>
e.key === "Escape" && navigate("/blog");
e.key === "Escape" && navigate("/blog")(e);
document.addEventListener("keydown", handler);
return () => document.removeEventListener("keydown", handler);
@ -205,9 +206,9 @@ const BlogHome: React.FC = () => {
const path = getBlogPath(article);
return (
<Link
<span
key={path}
to={path}
onClick={() => navigate(path)}
className={css`
display: flex;
flex-direction: column;
@ -233,7 +234,7 @@ const BlogHome: React.FC = () => {
<ArticleSubHeader article={article} />
<Spacer />
<p>{snippet}</p>
</Link>
</span>
);
})}
</div>

6
src/pages/blog/components/BlogContent.tsx

@ -1,5 +1,5 @@
import React, { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import useLocation from "wouter/use-location";
import { marked } from "marked";
import { Article, blog, getBlogPath, nextAndPrev } from "../../../data";
import "../../../blog.css";
@ -113,12 +113,12 @@ const btn = css`
export const BlogPost: React.FC = () => {
const navigate = useNav();
const location = useLocation();
const [location] = useLocation();
const [content, setContent] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(true);
const [year, slug] = location.pathname.split("/").slice(-2);
const [year, slug] = location.split("/").slice(-2);
const article = blog[year]?.[slug];
const [next, prev] = nextAndPrev(year, slug);

10
src/pages/main/404.tsx

@ -1,16 +1,18 @@
import React from "react";
import { Link } from "react-router-dom";
import Container from "../../components/Container";
import { useNav } from "../../util";
function Home() {
const navigate = useNav();
return (
<Container>
<h1>Nothing here</h1>
<p>
404. Back to{" "}
<b>
<Link to="/">MKRhere?</Link>
</b>
<a href="/" onClick={navigate("/")}>
MKRhere?
</a>
</p>
</Container>
);

14
src/pages/main/Contact.tsx

@ -8,7 +8,11 @@ const A = css`
`;
type Contact = {
[k: string]: { value: string; link?: string; replacer?: Record<string, string> };
[k: string]: {
value: string;
link?: string;
replacer?: Record<string, string>;
};
};
const CONTACT: Contact = {
@ -73,8 +77,8 @@ const Home: React.FC = () => {
return (
<Container
end
next="/"
arrowReversed={true}
className={css`
min-height: 50vh;
display: flex;
@ -112,7 +116,11 @@ const Home: React.FC = () => {
return (
<li key={key}>
{value.link ? (
<a className={A} href={value.link} target="_blank" rel="noreferrer">
<a
className={A}
href={value.link}
target="_blank"
rel="noreferrer">
{value.value}
</a>
) : (

7
src/util/index.ts

@ -1,5 +1,5 @@
import React from "react";
import { useNavigate } from "react-router-dom";
import useLocation from "wouter/use-location";
export const getTimeout = () => {
const clearables = new Set<number>();
@ -21,9 +21,10 @@ export const ellipses = (text: string, length: number = 100) =>
text.length > length ? text.slice(0, length - 3) + "..." : text;
export const useNav = () => {
const navigate = useNavigate();
const [, navigate] = useLocation();
return (link: string) => (e: React.MouseEvent) => {
return (link: string) => (e: React.MouseEvent | KeyboardEvent) => {
e?.preventDefault();
if (e.ctrlKey) return window.open(link, "_blank", "noreferrer noopener");
navigate(link);
};

9
vite.config.ts

@ -5,8 +5,13 @@ import svgr from "@svgr/rollup";
// https://vitejs.dev/config/
export default defineConfig({
server: { port: 3000 },
plugins: [react(), Object.assign(svgr({ ref: true, svgo: false }), { enforce: "pre" } as const)],
server: { port: 10000 },
plugins: [
react(),
Object.assign(svgr({ ref: true, svgo: false }), {
enforce: "pre",
} as const),
],
build: {
rollupOptions: {
input: {

Loading…
Cancel
Save