added routing
This commit is contained in:
parent
117603977a
commit
10cdb7bb5f
8 changed files with 489 additions and 82 deletions
|
|
@ -7,6 +7,8 @@
|
||||||
"express": "^4.21.2",
|
"express": "^4.21.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
"react-router": "^7.5.1",
|
||||||
|
"react-router-dom": "^7.5.1",
|
||||||
"react-scripts": "5.0.1"
|
"react-scripts": "5.0.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
91
src/App.js
91
src/App.js
|
|
@ -1,80 +1,23 @@
|
||||||
import React, { useState } from 'react';
|
import ReactDOM from "react-dom/client";
|
||||||
import './App.css';
|
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
||||||
import Header from './components/Header';
|
import Layout from "./pages/Layout";
|
||||||
import ProjectCard from './components/ProjectCard';
|
import Dashboard from "./pages/Dashboard";
|
||||||
import ProjectDetails from './components/ProjectDetails';
|
|
||||||
import forgejoLogo from './assets/forgejo.svg'
|
|
||||||
import githubLogo from './assets/github-mark-white.svg'
|
|
||||||
import LinkedinLogo from './assets/linkedIn.svg'
|
|
||||||
import projects from './data/projects';
|
import projects from './data/projects';
|
||||||
|
|
||||||
function App() {
|
export default function App() {
|
||||||
const [selectedProjectId, setSelectedProjectId] = useState(null);
|
|
||||||
|
|
||||||
const handleProjectClick = (projectId) => {
|
|
||||||
setSelectedProjectId(projectId);
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleBackClick = () => {
|
|
||||||
setSelectedProjectId(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectedProject = selectedProjectId ? projects.find(p => p.id === selectedProjectId) : null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="app">
|
<BrowserRouter>
|
||||||
<Header
|
<Routes>
|
||||||
onBackClick={handleBackClick}
|
<Route path="/" element={<Layout />}>
|
||||||
showBackButton={selectedProjectId !== null}
|
<Route index element={<Dashboard projectId={null}/>} />
|
||||||
/>
|
{projects.map(item => {
|
||||||
|
return(<Route path={item.id} element={<Dashboard projectId={item.id}/>} />)
|
||||||
<main className="app-content">
|
})}
|
||||||
{selectedProject ? (
|
</Route>
|
||||||
<ProjectDetails project={selectedProject} />
|
</Routes>
|
||||||
) : (
|
</BrowserRouter>
|
||||||
<div className="projects-list">
|
|
||||||
<div className="intro">
|
|
||||||
<h2>Freelance Development Experience</h2>
|
|
||||||
<p>
|
|
||||||
Below is a portfolio of my freelance projects.
|
|
||||||
Each project represents solutions to complex problems across various domains. This site is hosted on my rural farm in Northern, Ontario, Canada. If the site is down its most likely due to weather conditions like a blizzard if its winter. Relavent Links in the footer unfortunately a significant amount of my professional work is locked in private git, code commit and gitlab repos. If you've been given this site please feel free to contact me for more details.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
This site is a minimal React site, hosted on my own git server with a custom CI/CD pipline hooked up to pm2 for loadbalancing across a proxmox cluster (mainly for other stuff but it hosts this site too). The images are hosted via Google drive so if too many people hit the site the images will stop loading. Thanks for your understanding.
|
|
||||||
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{projects.map(project => (
|
|
||||||
<ProjectCard
|
|
||||||
key={project.id}
|
|
||||||
project={project}
|
|
||||||
onClick={handleProjectClick}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer className="app-footer">
|
|
||||||
<div className="footer-content">
|
|
||||||
<p>© {new Date().getFullYear()} Comet Technologies | All Rights Reserved</p>
|
|
||||||
<div className="social-links">
|
|
||||||
<a href="https://github.com/2ManyProjects" target="_blank" rel="noopener noreferrer" className="social-icon">
|
|
||||||
<img src={githubLogo} alt="Github" width="24" height="24" />
|
|
||||||
</a>
|
|
||||||
<a href="https://git.2many.ca/root?tab=activity" target="_blank" rel="noopener noreferrer" className="social-icon">
|
|
||||||
<img src={forgejoLogo} alt="Forgejo" width="24" height="24" />
|
|
||||||
</a>
|
|
||||||
<a href="https://www.linkedin.com/in/shaiv-kamat-a39ba514a/" target="_blank" rel="noopener noreferrer" className="social-icon">
|
|
||||||
<img src={LinkedinLogo} alt="Linkedin" width="24" height="24" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||||
|
root.render(<App />);
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
const Header = ({ onBackClick, showBackButton }) => {
|
const Header = ({ onBackClick, showBackButton }) => {
|
||||||
return (
|
return (
|
||||||
<header className="app-header">
|
<header className="app-header">
|
||||||
<div className="header-content">
|
<div className="header-content">
|
||||||
{showBackButton && (
|
{showBackButton && (
|
||||||
<button className="back-button" onClick={onBackClick}>
|
<Link to={"/"} style={{textDecorationColor: "transparent"}}>
|
||||||
|
<button className="back-button">
|
||||||
← Back to Projects
|
← Back to Projects
|
||||||
</button>
|
</button>
|
||||||
|
</Link>
|
||||||
)}
|
)}
|
||||||
<h1>Comet Technologies</h1>
|
<h1>Comet Technologies</h1>
|
||||||
<p className="tagline">You need it, I'll build it</p>
|
<p className="tagline">You need it, I'll build it</p>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import RenderChips from './RenderChips';
|
import RenderChips from './RenderChips';
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
|
||||||
const ProjectCard = ({ project, onClick }) => {
|
const ProjectCard = ({ project, onClick }) => {
|
||||||
|
|
@ -8,7 +9,7 @@ const ProjectCard = ({ project, onClick }) => {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="project-card" onClick={() => onClick(project.id)}>
|
<Link className="project-card" to={project.id} style={{textDecorationColor: "transparent"}}>
|
||||||
<h3>{project.title}</h3>
|
<h3>{project.title}</h3>
|
||||||
|
|
||||||
{project.langs && <RenderChips langs={project.langs} type='lang'/>}
|
{project.langs && <RenderChips langs={project.langs} type='lang'/>}
|
||||||
|
|
@ -22,7 +23,7 @@ const ProjectCard = ({ project, onClick }) => {
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="view-details">View Details</div>
|
<div className="view-details">View Details</div>
|
||||||
</div>
|
</Link>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import './App.css';
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||||
|
|
|
||||||
344
src/pages/Dashboard.css
Normal file
344
src/pages/Dashboard.css
Normal file
|
|
@ -0,0 +1,344 @@
|
||||||
|
/* Base Styles */
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header Styles */
|
||||||
|
.app-header {
|
||||||
|
background-color: #1a1a2e;
|
||||||
|
color: white;
|
||||||
|
padding: 2rem 1rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-button {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
font-size: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-button:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-header h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagline {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Content */
|
||||||
|
.app-content {
|
||||||
|
flex: 1;
|
||||||
|
padding: 2rem 1rem;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Project List */
|
||||||
|
.projects-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro h2 {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro p {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Project Card */
|
||||||
|
.project-card {
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
padding: 1.5rem;
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-card h3 {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
color: #1a1a2e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-summary {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-details {
|
||||||
|
text-align: right;
|
||||||
|
color: #16213e;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Project Details */
|
||||||
|
.project-details {
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-details h2 {
|
||||||
|
color: #1a1a2e;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-carousel {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-description p {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-size: 1.05rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Carousel Styles */
|
||||||
|
.carousel {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
position: relative;
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-image-container {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-image {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-button {
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-button:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-counter {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
right: 10px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
color: white;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-loading, .carousel-empty {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 300px;
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
color: #555;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
.app-footer {
|
||||||
|
background-color: #1a1a2e;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 1.5rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
.footer-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-links {
|
||||||
|
display: flex;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.5);
|
||||||
|
color: white;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-icon:hover {
|
||||||
|
color: #4361ee;
|
||||||
|
border-color: #4361ee;
|
||||||
|
transform: translateY(-3px);
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-icon svg {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Chip styling */
|
||||||
|
.chips-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin: 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 1px 12px;
|
||||||
|
border-radius: 16px;
|
||||||
|
font-size: 0.6rem;
|
||||||
|
font-weight: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip-large {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 1px 16px;
|
||||||
|
border-radius: 16px;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 750;
|
||||||
|
}
|
||||||
|
.lang-chip {
|
||||||
|
background-color: #e0f2ff;
|
||||||
|
color: #0366d6;
|
||||||
|
border: 1px solid #79b8ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.software-chip {
|
||||||
|
background-color: #f3e8ff;
|
||||||
|
color: #5a32a3;
|
||||||
|
border: 1px solid #d1bef2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-details {
|
||||||
|
margin-top: auto;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive styles */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.header-content {
|
||||||
|
padding: 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-button {
|
||||||
|
position: static;
|
||||||
|
transform: none;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-details {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-image-container {
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.app-header h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-image-container {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.footer-content {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
.social-links {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
78
src/pages/Dashboard.js
Normal file
78
src/pages/Dashboard.js
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import './Dashboard.css';
|
||||||
|
import Header from '../components/Header';
|
||||||
|
import ProjectCard from '../components/ProjectCard';
|
||||||
|
import ProjectDetails from '../components/ProjectDetails';
|
||||||
|
import forgejoLogo from '../assets/forgejo.svg'
|
||||||
|
import githubLogo from '../assets/github-mark-white.svg'
|
||||||
|
import LinkedinLogo from '../assets/linkedIn.svg'
|
||||||
|
import projects from '../data/projects';
|
||||||
|
|
||||||
|
function Dashboard({projectId}) {
|
||||||
|
const [selectedProjectId, setSelectedProjectId] = useState(projectId);
|
||||||
|
|
||||||
|
useEffect(() => {setSelectedProjectId(projectId)}, [projectId])
|
||||||
|
|
||||||
|
const handleProjectClick = (projectId) => {
|
||||||
|
setSelectedProjectId(projectId);
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const selectedProject = selectedProjectId ? projects.find(p => p.id === selectedProjectId) : null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="app">
|
||||||
|
<Header
|
||||||
|
showBackButton={selectedProjectId !== null}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<main className="app-content">
|
||||||
|
{selectedProject ? (
|
||||||
|
<ProjectDetails project={selectedProject} />
|
||||||
|
) : (
|
||||||
|
<div className="projects-list">
|
||||||
|
<div className="intro">
|
||||||
|
<h2>Freelance Development Experience</h2>
|
||||||
|
<p>
|
||||||
|
Below is a portfolio of my freelance projects.
|
||||||
|
Each project represents solutions to complex problems across various domains. This site is hosted on my rural farm in Northern, Ontario, Canada. If the site is down its most likely due to weather conditions like a blizzard if its winter. Relavent Links in the footer unfortunately a significant amount of my professional work is locked in private git, code commit and gitlab repos. If you've been given this site please feel free to contact me for more details.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This site is a minimal React site, hosted on my own git server with a custom CI/CD pipline hooked up to pm2 for loadbalancing across a proxmox cluster (mainly for other stuff but it hosts this site too). The images are hosted via Google drive so if too many people hit the site the images will stop loading. Thanks for your understanding.
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{projects.map(project => (
|
||||||
|
<ProjectCard
|
||||||
|
key={project.id}
|
||||||
|
project={project}
|
||||||
|
onClick={handleProjectClick}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer className="app-footer">
|
||||||
|
<div className="footer-content">
|
||||||
|
<p>© {new Date().getFullYear()} Comet Technologies | All Rights Reserved</p>
|
||||||
|
<div className="social-links">
|
||||||
|
<a href="https://github.com/2ManyProjects" target="_blank" rel="noopener noreferrer" className="social-icon">
|
||||||
|
<img src={githubLogo} alt="Github" width="24" height="24" />
|
||||||
|
</a>
|
||||||
|
<a href="https://git.2many.ca/root?tab=activity" target="_blank" rel="noopener noreferrer" className="social-icon">
|
||||||
|
<img src={forgejoLogo} alt="Forgejo" width="24" height="24" />
|
||||||
|
</a>
|
||||||
|
<a href="https://www.linkedin.com/in/shaiv-kamat-a39ba514a/" target="_blank" rel="noopener noreferrer" className="social-icon">
|
||||||
|
<img src={LinkedinLogo} alt="Linkedin" width="24" height="24" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Dashboard;
|
||||||
37
src/pages/Layout.js
Normal file
37
src/pages/Layout.js
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { Outlet } from "react-router-dom";
|
||||||
|
|
||||||
|
const Layout = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Outlet />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Layout;
|
||||||
|
|
||||||
|
/*
|
||||||
|
import ReactDOM from "react-dom/client";
|
||||||
|
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
||||||
|
import Layout from "./pages/Layout";
|
||||||
|
import Dashboard from "./pages/Dashboard";
|
||||||
|
import projects from './data/projects';
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return (
|
||||||
|
<BrowserRouter>
|
||||||
|
<Routes>
|
||||||
|
<Route path="/" element={<Layout />}>
|
||||||
|
<Route index element={<Dashboard projectId={null}/>} />
|
||||||
|
{projects.map(item => {
|
||||||
|
return(<Route path={item.id} element={<Dashboard projectId={item.id}/>} />)
|
||||||
|
})}
|
||||||
|
</Route>
|
||||||
|
</Routes>
|
||||||
|
</BrowserRouter>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||||
|
root.render(<App />);
|
||||||
|
*/
|
||||||
Loading…
Reference in a new issue