Merge pull request 'feature/detailsProject' (#28) from feature/detailsProject into dev
Reviewed-on: #28
This commit is contained in:
commit
a706f065a7
@ -1,11 +1,13 @@
|
||||
# To do
|
||||
|
||||
- revoir fonction de tri par age car problème entre 1 date et 2 des fois
|
||||
- Refaire les images qui vont pas
|
||||
- Faire une page explicative par projet
|
||||
- Faire du responsive
|
||||
- utiliser les vraies fonctions de fastapi
|
||||
|
||||
## Plus tard
|
||||
- Régler problème de scoll entre page
|
||||
- voir quoi mettre à droite des pages de details
|
||||
- Régler problème de scroll entre page
|
||||
- Refaire la section des skills
|
||||
|
||||
|
||||
@ -13,4 +15,5 @@
|
||||
|
||||
`npm install`
|
||||
`npm run dev`
|
||||
`npm install react-router-dom`
|
||||
`npm install react-router-dom`
|
||||
`npm install react-markdown remark-gfm`
|
||||
|
||||
1476
package-lock.json
generated
1476
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,9 @@
|
||||
"dependencies": {
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-router-dom": "^7.8.2"
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-router-dom": "^7.8.2",
|
||||
"remark-gfm": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.25.0",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.5 MiB |
BIN
public/assets/images/projectDetailsHeadband.png
Normal file
BIN
public/assets/images/projectDetailsHeadband.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 MiB |
@ -1,3 +1,4 @@
|
||||
#root {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
@ -2,6 +2,7 @@ import './App.css'
|
||||
import { Routes, Route, Link } from 'react-router-dom';
|
||||
import HomePage from './pages/HomePage.jsx';
|
||||
import ProjectsPage from './pages/ProjectsPage';
|
||||
import ProjectDetailsPage from "./pages/ProjectDetailsPage.jsx";
|
||||
|
||||
|
||||
function App() {
|
||||
@ -9,6 +10,7 @@ function App() {
|
||||
<Routes>
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="/projects" element={<ProjectsPage />} />
|
||||
<Route path="/projectDetails/:id" element={<ProjectDetailsPage />} />
|
||||
</Routes>
|
||||
)
|
||||
}
|
||||
|
||||
@ -24,10 +24,6 @@
|
||||
justify-content: center;
|
||||
color: var(--text-color);
|
||||
transition: color 0.3s ease, transform 0.3s ease;
|
||||
svg{
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,12 +10,12 @@ function Footer() {
|
||||
</div>
|
||||
<div className="footer-links">
|
||||
<a href="https://github.com/Giovanni-Josserand" target="_blank" rel="noopener noreferrer">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24" fill="currentColor">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24" fill="currentColor" width="24px" height="24px">
|
||||
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://gitea.josserand.ovh/Giovanni-Josserand" target="_blank" rel="noopener noreferrer">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24" fill="currentColor">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24" fill="currentColor" width="24px" height="24px">
|
||||
<path d="M4.209 4.603c-.247 0-.525.02-.84.088-.333.07-1.28.283-2.054 1.027C-.403 7.25.035 9.685.089 10.052c.065.446.263 1.687 1.21 2.768 1.749 2.141 5.513 2.092 5.513 2.092s.462 1.103 1.168 2.119c.955 1.263 1.936 2.248 2.89 2.367 2.406 0 7.212-.004 7.212-.004s.458.004 1.08-.394c.535-.324 1.013-.893 1.013-.893s.492-.527 1.18-1.73c.21-.37.385-.729.538-1.068 0 0 2.107-4.471 2.107-8.823-.042-1.318-.367-1.55-.443-1.627-.156-.156-.366-.153-.366-.153s-4.475.252-6.792.306c-.508.011-1.012.023-1.512.027v4.474l-.634-.301c0-1.39-.004-4.17-.004-4.17-1.107.016-3.405-.084-3.405-.084s-5.399-.27-5.987-.324c-.187-.011-.401-.032-.648-.032zm.354 1.832h.111s.271 2.269.6 3.597C5.549 11.147 6.22 13 6.22 13s-.996-.119-1.641-.348c-.99-.324-1.409-.714-1.409-.714s-.73-.511-1.096-1.52C1.444 8.73 2.021 7.7 2.021 7.7s.32-.859 1.47-1.145c.395-.106.863-.12 1.072-.12zm8.33 2.554c.26.003.509.127.509.127l.868.422-.529 1.075a.686.686 0 0 0-.614.359.685.685 0 0 0 .072.756l-.939 1.924a.69.69 0 0 0-.66.527.687.687 0 0 0 .347.763.686.686 0 0 0 .867-.206.688.688 0 0 0-.069-.882l.916-1.874a.667.667 0 0 0 .237-.02.657.657 0 0 0 .271-.137 8.826 8.826 0 0 1 1.016.512.761.761 0 0 1 .286.282c.073.21-.073.569-.073.569-.087.29-.702 1.55-.702 1.55a.692.692 0 0 0-.676.477.681.681 0 1 0 1.157-.252c.073-.141.141-.282.214-.431.19-.397.515-1.16.515-1.16.035-.066.218-.394.103-.814-.095-.435-.48-.638-.48-.638-.467-.301-1.116-.58-1.116-.58s0-.156-.042-.27a.688.688 0 0 0-.148-.241l.516-1.062 2.89 1.401s.48.218.583.619c.073.282-.019.534-.069.657-.24.587-2.1 4.317-2.1 4.317s-.232.554-.748.588a1.065 1.065 0 0 1-.393-.045l-.202-.08-4.31-2.1s-.417-.218-.49-.596c-.083-.31.104-.691.104-.691l2.073-4.272s.183-.37.466-.497a.855.855 0 0 1 .35-.077z"/>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
background: none;
|
||||
font-size: 15px;
|
||||
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
|
||||
172
src/components/ProjectDetails/ProjectDetails.css
Normal file
172
src/components/ProjectDetails/ProjectDetails.css
Normal file
@ -0,0 +1,172 @@
|
||||
.project-details {
|
||||
display: flex;
|
||||
width: 70%;
|
||||
margin: 0 15% 0 15%;
|
||||
gap: 4%;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.nav-bar{
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
height: 280px;
|
||||
|
||||
background-image: url("/public/assets/images/projectDetailsHeadband.png");
|
||||
background-size: cover;
|
||||
|
||||
&::after { /* Utilise un pseudo-élément pour le dégradé */
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
background: linear-gradient(to top, #0D0D0D 0%, rgba(26, 26, 26, 0) 100%);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.project-details-header{
|
||||
width: 100%;
|
||||
border-bottom: 2px solid #333;
|
||||
}
|
||||
|
||||
.project-details-header h1{
|
||||
color: var(--title-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin: 0;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.project-details-container {
|
||||
width: 92%;
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
padding: 0 4%;
|
||||
}
|
||||
|
||||
.project-details-content {
|
||||
width: 80%
|
||||
}
|
||||
|
||||
.project-details-content h2 {
|
||||
margin-top: 2rem;
|
||||
color: var(--title-color);
|
||||
border-left: 4px solid var(--important-color);
|
||||
padding-left: 0.75rem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.project-details-years {
|
||||
color : var(--text-color);
|
||||
margin : 0;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.project-details-short-description{
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.project-details-header ul{
|
||||
display: flex;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
|
||||
aside {
|
||||
width: 20%;
|
||||
height: fit-content;
|
||||
position: sticky;
|
||||
top: 150px;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.aside-title {
|
||||
font-weight: bold;
|
||||
color: var(--title-color);
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
|
||||
aside ul{
|
||||
border-left: 2px solid #333;
|
||||
list-style: none;
|
||||
padding: 0 0 0 1em;
|
||||
}
|
||||
|
||||
aside ul li {
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
aside ul li a {
|
||||
text-decoration: none;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
aside ul li a:hover {
|
||||
color: var(--title-color)
|
||||
}
|
||||
|
||||
.return-button{
|
||||
position: absolute;
|
||||
top: 2em;
|
||||
left: 20px;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 7px;
|
||||
cursor: pointer;
|
||||
z-index: 10;
|
||||
transition: background-color 0.3s ease;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.return-button:hover {
|
||||
background: rgba(100,100,100, 0.5);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.return-button svg {
|
||||
color: var(--text-color);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.return-button:hover svg {
|
||||
color: var(--title-color);
|
||||
}
|
||||
|
||||
.repo_link {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
svg{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--text-color);
|
||||
transition: color 0.3s ease, transform 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.repo_link svg:hover {
|
||||
color: var(--title-color);
|
||||
}
|
||||
|
||||
.project-details-header-left{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
}
|
||||
117
src/components/ProjectDetails/ProjectDetails.jsx
Normal file
117
src/components/ProjectDetails/ProjectDetails.jsx
Normal file
@ -0,0 +1,117 @@
|
||||
import "./ProjectDetails.css"
|
||||
import SkillCard from "../SkillCard/SkillCard.jsx";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import NavBar from "../NavBar/NavBar.jsx";
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import {useNavigate} from "react-router-dom";
|
||||
|
||||
|
||||
function ProjectDetails({project}) {
|
||||
const [mdTitle, setMdTitle] = useState([]);
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() =>{
|
||||
if (!project.long_description) return;
|
||||
const matches = [...project.long_description.matchAll(/^## (?!#)(.+)$/gm)];
|
||||
setMdTitle(matches.map(match => match[1].trim()));
|
||||
}, [project.long_description])
|
||||
|
||||
|
||||
const handleSummaryClick = (event, anchor) => {
|
||||
event.preventDefault();
|
||||
const element = document.getElementById(anchor);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button className="return-button" onClick={() => navigate(-1)}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" width="24px" height="24px" fill="currentColor">
|
||||
<path d="m313-440 224 224-57 56-320-320 320-320 57 56-224 224h487v80H313Z"/>
|
||||
</svg>
|
||||
</button>
|
||||
<div className="nav-bar">
|
||||
<NavBar/>
|
||||
</div>
|
||||
<div className="project-details">
|
||||
<div className="project-details-header">
|
||||
<h1>
|
||||
<div className="project-details-header-left">
|
||||
{project.title}
|
||||
{project.school ? (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" fill="#D95F46" width="1em" height="1em">
|
||||
<path d="M80 259.8L289.2 345.9C299 349.9 309.4 352 320 352C330.6 352 341 349.9 350.8 345.9L593.2 246.1C602.2 242.4 608 233.7 608 224C608 214.3 602.2 205.6 593.2 201.9L350.8 102.1C341 98.1 330.6 96 320 96C309.4 96 299 98.1 289.2 102.1L46.8 201.9C37.8 205.6 32 214.3 32 224L32 520C32 533.3 42.7 544 56 544C69.3 544 80 533.3 80 520L80 259.8zM128 331.5L128 448C128 501 214 544 320 544C426 544 512 501 512 448L512 331.4L369.1 390.3C353.5 396.7 336.9 400 320 400C303.1 400 286.5 396.7 270.9 390.3L128 331.4z"/>
|
||||
</svg>
|
||||
) : null}
|
||||
</div>
|
||||
{typeof project.repo_link === "string" && project.repo_link.length > 0 ? (
|
||||
<a href={project.repo_link} className="repo_link">
|
||||
{project.repo_link.includes("github") ? (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24" fill="currentColor" width="1em" height="1em">
|
||||
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
|
||||
</svg>
|
||||
) : (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24" fill="currentColor" width="1em" height="1em">
|
||||
<path d="M4.209 4.603c-.247 0-.525.02-.84.088-.333.07-1.28.283-2.054 1.027C-.403 7.25.035 9.685.089 10.052c.065.446.263 1.687 1.21 2.768 1.749 2.141 5.513 2.092 5.513 2.092s.462 1.103 1.168 2.119c.955 1.263 1.936 2.248 2.89 2.367 2.406 0 7.212-.004 7.212-.004s.458.004 1.08-.394c.535-.324 1.013-.893 1.013-.893s.492-.527 1.18-1.73c.21-.37.385-.729.538-1.068 0 0 2.107-4.471 2.107-8.823-.042-1.318-.367-1.55-.443-1.627-.156-.156-.366-.153-.366-.153s-4.475.252-6.792.306c-.508.011-1.012.023-1.512.027v4.474l-.634-.301c0-1.39-.004-4.17-.004-4.17-1.107.016-3.405-.084-3.405-.084s-5.399-.27-5.987-.324c-.187-.011-.401-.032-.648-.032zm.354 1.832h.111s.271 2.269.6 3.597C5.549 11.147 6.22 13 6.22 13s-.996-.119-1.641-.348c-.99-.324-1.409-.714-1.409-.714s-.73-.511-1.096-1.52C1.444 8.73 2.021 7.7 2.021 7.7s.32-.859 1.47-1.145c.395-.106.863-.12 1.072-.12zm8.33 2.554c.26.003.509.127.509.127l.868.422-.529 1.075a.686.686 0 0 0-.614.359.685.685 0 0 0 .072.756l-.939 1.924a.69.69 0 0 0-.66.527.687.687 0 0 0 .347.763.686.686 0 0 0 .867-.206.688.688 0 0 0-.069-.882l.916-1.874a.667.667 0 0 0 .237-.02.657.657 0 0 0 .271-.137 8.826 8.826 0 0 1 1.016.512.761.761 0 0 1 .286.282c.073.21-.073.569-.073.569-.087.29-.702 1.55-.702 1.55a.692.692 0 0 0-.676.477.681.681 0 1 0 1.157-.252c.073-.141.141-.282.214-.431.19-.397.515-1.16.515-1.16.035-.066.218-.394.103-.814-.095-.435-.48-.638-.48-.638-.467-.301-1.116-.58-1.116-.58s0-.156-.042-.27a.688.688 0 0 0-.148-.241l.516-1.062 2.89 1.401s.48.218.583.619c.073.282-.019.534-.069.657-.24.587-2.1 4.317-2.1 4.317s-.232.554-.748.588a1.065 1.065 0 0 1-.393-.045l-.202-.08-4.31-2.1s-.417-.218-.49-.596c-.083-.31.104-.691.104-.691l2.073-4.272s.183-.37.466-.497a.855.855 0 0 1 .35-.077z"/>
|
||||
</svg>
|
||||
)}
|
||||
</a>
|
||||
) : null}
|
||||
|
||||
</h1>
|
||||
{project.end_year === null ? (
|
||||
<p className="project-details-years">{project.beginning_year + ' – in progress'}</p>
|
||||
) : project.beginning_year === project.end_year ? (
|
||||
<p className="project-details-years">{project.beginning_year}</p>
|
||||
) : (
|
||||
<p className="project-details-years">{project.beginning_year + ' – ' + project.end_year}</p>
|
||||
)}
|
||||
<p className="project-details-short-description">{project.short_description}</p>
|
||||
<ul>
|
||||
{project.skills && project.skills.map((skill) => (
|
||||
<li>
|
||||
<SkillCard text={skill} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="project-details-container">
|
||||
<div className="project-details-content">
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
h2({node, ...props}) {
|
||||
const id = String(props.children).toLowerCase().replace(/\s+/g, "-");
|
||||
return <h2 id={id} {...props} />;
|
||||
}
|
||||
}}
|
||||
>
|
||||
{project.long_description}
|
||||
</ReactMarkdown>
|
||||
|
||||
</div>
|
||||
<aside>
|
||||
<ul>
|
||||
{mdTitle.map(title => {
|
||||
const anchor = title.toLowerCase().replace(/\s+/g, "-");
|
||||
return (
|
||||
<li key={anchor}>
|
||||
<a href={`#${anchor}`} onClick={(e) => handleSummaryClick(e, anchor)}>
|
||||
{title}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default ProjectDetails
|
||||
@ -7,7 +7,6 @@
|
||||
|
||||
.show-more-container {
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
||||
.projects-link {
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
.single-project:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.single-project-top {
|
||||
@ -115,19 +116,6 @@
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.single-project-link {
|
||||
color: var(--text-color);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
margin-bottom : 0;
|
||||
}
|
||||
|
||||
.single-project-link:hover {
|
||||
cursor: pointer;
|
||||
color: var(--title-color);
|
||||
}
|
||||
|
||||
|
||||
.single-project-years{
|
||||
color : var(--text-color);
|
||||
margin : 0;
|
||||
|
||||
@ -1,53 +1,59 @@
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import SkillCard from "../SkillCard/SkillCard.jsx";
|
||||
import "./SingleProject.css";
|
||||
import {Link, useNavigate} from "react-router-dom";
|
||||
|
||||
function SingleProject({ image, title, description, skills, id, school, beginningYear, endYear }) {
|
||||
const color = ["blue", "green", "purple", "red", "yellow"]
|
||||
const navigate = useNavigate();
|
||||
|
||||
const clickProject = () => {
|
||||
navigate(`/projectDetails/${id}`);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="single-project">
|
||||
<div className="single-project-top">
|
||||
<img src={`/assets/images/projects/${image}/${image}_1.png`} alt={image}/>
|
||||
</div>
|
||||
<div className="single-project-bottom">
|
||||
<div className="single-project-bottom-header">
|
||||
<div className="single-project-title-wrapper">
|
||||
<div className={`single-project-line color-${color[(id-1)%color.length]}`}></div>
|
||||
<h3 className="single-project-title">
|
||||
{title}
|
||||
{school ? (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" fill="#D95F46" width="1.25em" height="1.25em">
|
||||
<path d="M80 259.8L289.2 345.9C299 349.9 309.4 352 320 352C330.6 352 341 349.9 350.8 345.9L593.2 246.1C602.2 242.4 608 233.7 608 224C608 214.3 602.2 205.6 593.2 201.9L350.8 102.1C341 98.1 330.6 96 320 96C309.4 96 299 98.1 289.2 102.1L46.8 201.9C37.8 205.6 32 214.3 32 224L32 520C32 533.3 42.7 544 56 544C69.3 544 80 533.3 80 520L80 259.8zM128 331.5L128 448C128 501 214 544 320 544C426 544 512 501 512 448L512 331.4L369.1 390.3C353.5 396.7 336.9 400 320 400C303.1 400 286.5 396.7 270.9 390.3L128 331.4z"/>
|
||||
</svg>
|
||||
) : null}
|
||||
</h3>
|
||||
</div>
|
||||
{endYear === null ? (
|
||||
<p className="single-project-years">{beginningYear + ' – in progress'}</p>
|
||||
) : beginningYear === endYear ? (
|
||||
<div className="single-project" onClick={clickProject}>
|
||||
<div className="single-project-top">
|
||||
<img src={`/assets/images/projects/${image}/${image}_1.png`} alt={image}/>
|
||||
</div>
|
||||
<div className="single-project-bottom">
|
||||
<div className="single-project-bottom-header">
|
||||
<div className="single-project-title-wrapper">
|
||||
<div className={`single-project-line color-${color[(id-1)%color.length]}`}></div>
|
||||
<h3 className="single-project-title">
|
||||
{title}
|
||||
{school ? (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" fill="#D95F46" width="1em" height="1em">
|
||||
<path d="M80 259.8L289.2 345.9C299 349.9 309.4 352 320 352C330.6 352 341 349.9 350.8 345.9L593.2 246.1C602.2 242.4 608 233.7 608 224C608 214.3 602.2 205.6 593.2 201.9L350.8 102.1C341 98.1 330.6 96 320 96C309.4 96 299 98.1 289.2 102.1L46.8 201.9C37.8 205.6 32 214.3 32 224L32 520C32 533.3 42.7 544 56 544C69.3 544 80 533.3 80 520L80 259.8zM128 331.5L128 448C128 501 214 544 320 544C426 544 512 501 512 448L512 331.4L369.1 390.3C353.5 396.7 336.9 400 320 400C303.1 400 286.5 396.7 270.9 390.3L128 331.4z"/>
|
||||
</svg>
|
||||
) : null}
|
||||
</h3>
|
||||
</div>
|
||||
{endYear === null ? (
|
||||
<p className="single-project-years">{beginningYear + ' – in progress'}</p>
|
||||
) : beginningYear === endYear ? (
|
||||
<p className="single-project-years">{beginningYear}</p>
|
||||
) : (
|
||||
<p className="single-project-years">{beginningYear + ' – ' + endYear}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="single-project-bottom-container">
|
||||
<p className="single-project-description" style={{ whiteSpace: "pre-line" }}>
|
||||
{description}
|
||||
</p>
|
||||
) : (
|
||||
<p className="single-project-years">{beginningYear + ' – ' + endYear}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="single-project-bottom-container">
|
||||
<p className="single-project-description" style={{ whiteSpace: "pre-line" }}>
|
||||
{description}
|
||||
</p>
|
||||
|
||||
<ul className="single-project-skills-list">
|
||||
{skills.map((skill) => (
|
||||
<li key={skill}>
|
||||
<SkillCard text={skill} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<ul className="single-project-skills-list">
|
||||
{skills.map((skill) => (
|
||||
<li key={skill}>
|
||||
<SkillCard text={skill} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<p className="single-project-link">Learn more</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
font-weight: 400;
|
||||
background-color: #0D0D0D;
|
||||
--title-color: #EAEAEA;
|
||||
--text-color: #B0B0B0;
|
||||
--text-color: #7c7c7c;
|
||||
--important-color: #D95F46;
|
||||
}
|
||||
|
||||
@ -16,8 +16,6 @@ body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
|
||||
42
src/pages/ProjectDetailsPage.jsx
Normal file
42
src/pages/ProjectDetailsPage.jsx
Normal file
@ -0,0 +1,42 @@
|
||||
import { useParams } from "react-router-dom";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import NavBar from "../components/NavBar/NavBar.jsx";
|
||||
import ProjectDetails from "../components/ProjectDetails/ProjectDetails.jsx";
|
||||
import Footer from "../components/Footer/Footer.jsx";
|
||||
|
||||
function ProjectDetailsPage() {
|
||||
const { id } = useParams();
|
||||
const [project, setProject] = useState([]);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchProject = async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/longProjects/${id}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Erreur HTTP: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
setProject(data);
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
}
|
||||
};
|
||||
|
||||
fetchProject();
|
||||
}, [id]);
|
||||
|
||||
if (error) {
|
||||
return <p>Erreur : {error}</p>;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ProjectDetails project={project}/>
|
||||
<Footer/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ProjectDetailsPage;
|
||||
Loading…
x
Reference in New Issue
Block a user