Implement react routing

This commit is contained in:
Curt Spark 2024-04-13 12:16:18 +01:00
parent 3e48ca3c02
commit bffc070296
9 changed files with 178 additions and 68 deletions

42
package-lock.json generated
View File

@ -21,6 +21,7 @@
"css-loader": "^7.1.1", "css-loader": "^7.1.1",
"html-webpack-plugin": "^5.6.0", "html-webpack-plugin": "^5.6.0",
"prettier": "3.2.5", "prettier": "3.2.5",
"react-router-dom": "^6.22.3",
"style-loader": "^4.0.0", "style-loader": "^4.0.0",
"typescript": "^5.4.5", "typescript": "^5.4.5",
"webpack": "^5.91.0", "webpack": "^5.91.0",
@ -1915,6 +1916,15 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/@remix-run/router": {
"version": "1.15.3",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz",
"integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==",
"dev": true,
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@types/body-parser": { "node_modules/@types/body-parser": {
"version": "1.19.5", "version": "1.19.5",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
@ -5379,6 +5389,38 @@
"react": "^18.2.0" "react": "^18.2.0"
} }
}, },
"node_modules/react-router": {
"version": "6.22.3",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz",
"integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==",
"dev": true,
"dependencies": {
"@remix-run/router": "1.15.3"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/react-router-dom": {
"version": "6.22.3",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz",
"integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==",
"dev": true,
"dependencies": {
"@remix-run/router": "1.15.3",
"react-router": "6.22.3"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"react": ">=16.8",
"react-dom": ">=16.8"
}
},
"node_modules/readable-stream": { "node_modules/readable-stream": {
"version": "3.6.2", "version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",

View File

@ -6,7 +6,7 @@
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack", "build": "webpack",
"dev": "webpack-dev-server --mode development --open --hot" "dev": "webpack-dev-server --mode development --open --hot --history-api-fallback"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -20,6 +20,7 @@
"css-loader": "^7.1.1", "css-loader": "^7.1.1",
"html-webpack-plugin": "^5.6.0", "html-webpack-plugin": "^5.6.0",
"prettier": "3.2.5", "prettier": "3.2.5",
"react-router-dom": "^6.22.3",
"style-loader": "^4.0.0", "style-loader": "^4.0.0",
"typescript": "^5.4.5", "typescript": "^5.4.5",
"webpack": "^5.91.0", "webpack": "^5.91.0",

View File

@ -1,46 +1,29 @@
import * as React from "react"; import * as React from "react";
import BlogEntryCard from "./components/BlogEntryCard.tsx"; import { BrowserRouter, Routes, Route } from "react-router-dom";
import Navbar from "./components/Navbar.tsx"; import Navbar from "./components/Navbar.tsx";
import NavbarButton from "./components/NavbarButton.tsx"; import NavbarButton from "./components/NavbarButton.tsx";
export default function App() { import Home from "./pages/Home.tsx";
// A mock of what the data from the getBlogEntries JSON return would look like import Login from "./pages/Login.tsx";
const blogEntries = [ import About from "./pages/About.tsx";
{
blogImage:
"https://git.cspark.dev/avatars/1c230bfe7494b1a62932d94ed8558dc61189437b1b6e0cecdb0c45c3d899bea4?size=512",
blogTitle: "Test Blog Entry 1",
blogDatePosted: "12/04/2024 4PM", // In reality this would probably be an actual correct format/standardised timestamp
blogDescription: "This is a first blog entry test", // If no description, we'd want to get a small snippet of the intro of the blog
},
{
blogImage:
"https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png",
blogTitle: "Test Blog Entry 2",
blogDatePosted: "8/04/2024 6PM", // In reality this would probably be an actual correct format/standardised timestamp
blogDescription: "This is a test blog entry number 2", // If no description, we'd want to get a small snippet of the intro of the blog
},
];
export default function App() {
return ( return (
<main> <>
<Navbar> <BrowserRouter>
<NavbarButton></NavbarButton> <Navbar>
<NavbarButton></NavbarButton> <NavbarButton>Home</NavbarButton>
<NavbarButton></NavbarButton> <NavbarButton>Login</NavbarButton>
<NavbarButton></NavbarButton> <NavbarButton>About</NavbarButton>
</Navbar> </Navbar>
<div className="blogEntryGrid"> <Routes>
{blogEntries.map((item, index) => ( <Route path="/" exact element={<Home></Home>} />
<BlogEntryCard <Route path="/home" exact element={<Home></Home>} />
key={index} <Route path="/about" exact element={<About></About>} />
blogImage={item["blogImage"]} <Route path="/login" exact element={<Login></Login>} />
blogTitle={item["blogTitle"]} </Routes>
blogDatePosted={item["blogDatePosted"]} </BrowserRouter>
blogDescription={item["blogDescription"]} </>
></BlogEntryCard>
))}
</div>
</main>
); );
} }

View File

@ -1,18 +1,16 @@
import * as React from "react"; import * as React from "react";
import { Link } from "react-router-dom";
interface Props { interface Props {
blogImage: string; // This needs a placeholder/default variable children: string;
blogTitle: string;
blogDatePosted: string;
blogDescription: string;
} }
export default function NavbarButton() { export default function NavbarButton({ children }: Props) {
return ( return (
<> <>
<button className="navBarButton"> <Link to={children.toLowerCase()} className="navBarButton">
Hiiiii <p className="navBarButtonText">{children}</p>
</button> </Link>
</> </>
); );
} }

View File

@ -1,8 +1,12 @@
body { body {
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
background-color: white;
font-family: "consolas", sans-serif; font-family: "consolas", sans-serif;
background-color: white;
--nav-bar-height: 25px;
--blog-card-width: 18rem;
--blog-card-height: 20rem;
} }
a { a {
@ -11,15 +15,34 @@ a {
.navBar { .navBar {
width: 100%; width: 100%;
height: 30px; height: var(--nav-bar-height);
max-height: 30px; max-height: var(--nav-bar-height);
background-color: black; max-width: 100%;
display: grid; display: grid;
gap: 20px; gap: 10px;
padding: 10px; padding: 5px;
grid-auto-flow: column; grid-auto-flow: column;
grid-auto-rows: 100%; grid-auto-rows: 100%;
grid-auto-columns: 5rem; grid-auto-columns: 5rem;
background-color: black;
}
.navBarButton {
height: 100%;
width: 100%;
max-height: 100%;
max-width: 100%;
border-radius: 5px;
display: flex;
align-items: center;
justify-content: center;
background: white;
}
.navBarButtonText {
margin: 0px;
padding: 0px;
text-align: center;
} }
.blogEntryGrid { .blogEntryGrid {
@ -27,43 +50,43 @@ a {
gap: 20px; gap: 20px;
padding: 10px; padding: 10px;
grid-auto-flow: column; grid-auto-flow: column;
grid-auto-rows: 18rem; grid-auto-rows: var(--blog-card-height);
grid-auto-columns: 18rem; grid-auto-columns: var(--blog-card-width);
} }
.blogEntryCard { .blogEntryCard {
width: 18rem; width: var(--blog-card-width);
max-width: 18rem; height: var(--blog-card-height);
height: 20rem; max-width: var(--blog-card-width);
max-height: 20rem; max-height: var(--blog-card-height);
} }
.blogEntry { .blogEntry {
position: relative;
width: 100%; width: 100%;
height: 100%; height: 100%;
border-style: solid; border-style: solid;
border-width: 5px; border-width: 5px;
border-color: black;
border-radius: 10px; border-radius: 10px;
border-color: black;
background-color: white; background-color: white;
position: relative;
} }
.blogEntryImage { .blogEntryImage {
width: 18rem; width: var(--blog-card-width);
max-width: 18rem; max-width: var(--blog-card-width);
max-height: 18rem; max-height: var(--blog-card-width);
border-radius: 4px; border-radius: 4px;
} }
.blogEntryBody { .blogEntryBody {
background-color: grey;
padding: 20px;
position: absolute; position: absolute;
top: 8rem;
/* TODO: Need to switch to CSS grid positioning to sort this out */
width: 86%; width: 86%;
height: 45%; height: 45%;
padding: 20px;
top: 8rem;
/* TODO: Need to switch to CSS grid positioning to sort this out */
background-color: grey;
} }
.blogEntryTitle { .blogEntryTitle {

11
src/pages/About.tsx Normal file
View File

@ -0,0 +1,11 @@
import * as React from "react";
export default function About() {
return (
<main>
<h1>This is an about me.</h1>
<p>Developed by Curt Spark</p>
<a href="https://git.cspark.dev/Blorg">Link to Project Page</a>
</main>
);
}

39
src/pages/Home.tsx Normal file
View File

@ -0,0 +1,39 @@
import * as React from "react";
import BlogEntryCard from "./../components/BlogEntryCard.tsx";
export default function Home() {
// A mock of what the data from the getBlogEntries JSON return would look like
const blogEntries = [
{
blogImage:
"https://git.cspark.dev/avatars/1c230bfe7494b1a62932d94ed8558dc61189437b1b6e0cecdb0c45c3d899bea4?size=512",
blogTitle: "Test Blog Entry 1",
blogDatePosted: "12/04/2024 4PM", // In reality this would probably be an actual correct format/standardised timestamp
blogDescription: "This is a first blog entry test", // If no description, we'd want to get a small snippet of the intro of the blog
},
{
blogImage:
"https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png",
blogTitle: "Test Blog Entry 2",
blogDatePosted: "8/04/2024 6PM", // In reality this would probably be an actual correct format/standardised timestamp
blogDescription: "This is a test blog entry number 2", // If no description, we'd want to get a small snippet of the intro of the blog
},
];
return (
<main>
<div className="blogEntryGrid">
{blogEntries.map((item, index) => (
<BlogEntryCard
key={index}
blogImage={item["blogImage"]}
blogTitle={item["blogTitle"]}
blogDatePosted={item["blogDatePosted"]}
blogDescription={item["blogDescription"]}
></BlogEntryCard>
))}
</div>
</main>
);
}

9
src/pages/Login.tsx Normal file
View File

@ -0,0 +1,9 @@
import * as React from "react";
export default function Login() {
return (
<main>
<h1>Login Page</h1>
</main>
);
}

View File

@ -6,6 +6,10 @@ module.exports = {
output: { output: {
filename: "main.js", filename: "main.js",
path: path.resolve(__dirname, "dist"), path: path.resolve(__dirname, "dist"),
publicPath: "/",
},
devServer: {
historyApiFallback: true,
}, },
module: { module: {
rules: [ rules: [