Implement react routing
This commit is contained in:
parent
3e48ca3c02
commit
bffc070296
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
59
src/App.tsx
59
src/App.tsx
|
|
@ -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>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
export default function Login() {
|
||||||
|
return (
|
||||||
|
<main>
|
||||||
|
<h1>Login Page</h1>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -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: [
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue