optimization and moved link after description in project page

This commit is contained in:
kinou-p 2025-10-02 16:37:04 +02:00
parent 4895541c61
commit fb841cb17c
4 changed files with 73 additions and 67 deletions

View File

@ -4,6 +4,10 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<!-- Preload des ressources critiques -->
<link rel="preload" as="script" href="/src/main.tsx" />
<title>Alexandre Pommier - Portfolio</title> <title>Alexandre Pommier - Portfolio</title>
<meta name="description" content="Alexandre Pommier, étudiant en informatique à 42, développeur passionné par les technologies web et systèmes." /> <meta name="description" content="Alexandre Pommier, étudiant en informatique à 42, développeur passionné par les technologies web et systèmes." />
<meta name="author" content="Alexandre Pommier" /> <meta name="author" content="Alexandre Pommier" />
@ -17,10 +21,14 @@
<meta name="twitter:site" content="@lovable_dev" /> <meta name="twitter:site" content="@lovable_dev" />
<meta name="twitter:image" content="https://lovable.dev/opengraph-image-p98pqg.png" /> <meta name="twitter:image" content="https://lovable.dev/opengraph-image-p98pqg.png" />
<!-- Google Fonts --> <!-- Google Fonts - Optimisé avec display=swap et preload -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Montserrat:wght@400;500;600;700&display=swap" rel="stylesheet"> <link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Montserrat:wght@400;500;600;700&display=swap">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Montserrat:wght@400;500;600;700&display=swap" rel="stylesheet" media="print" onload="this.media='all'">
<noscript>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Montserrat:wght@400;500;600;700&display=swap" rel="stylesheet">
</noscript>
<!-- Google Tag Manager --> <!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':

View File

@ -8,11 +8,16 @@ export const ParticlesBackground = () => {
const { theme } = useTheme(); const { theme } = useTheme();
useEffect(() => { useEffect(() => {
initParticlesEngine(async (engine) => { // Retarder l'initialisation des particules pour ne pas bloquer le premier rendu
await loadSlim(engine); const timer = setTimeout(() => {
}).then(() => { initParticlesEngine(async (engine) => {
setInit(true); await loadSlim(engine);
}); }).then(() => {
setInit(true);
});
}, 1000); // Attendre 1 seconde après le chargement initial
return () => clearTimeout(timer);
}, []); }, []);
const particlesLoaded = async (container) => { const particlesLoaded = async (container) => {
@ -73,12 +78,12 @@ export const ParticlesBackground = () => {
density: { density: {
enable: true, enable: true,
}, },
value: 70, value: 70, // Réduit de 70 à 30 pour de meilleures performances
}, },
opacity: { opacity: {
value: { min: 0.1, max: theme === "dark" ? 0.5 : 0.6 }, value: { min: 0.1, max: theme === "dark" ? 0.5 : 0.6 },
animation: { animation: {
enable: true, enable: false, // Désactiver l'animation d'opacité pour meilleures performances
speed: 3, speed: 3,
sync: false, sync: false,
}, },
@ -89,14 +94,14 @@ export const ParticlesBackground = () => {
size: { size: {
value: { min: 0.1, max: 5 }, value: { min: 0.1, max: 5 },
animation: { animation: {
enable: true, enable: false, // Désactiver l'animation de taille pour meilleures performances
speed: 20, speed: 20,
sync: false, sync: false,
}, },
}, },
twinkle: { twinkle: {
lines: { lines: {
enable: true, enable: false, // Désactiver le scintillement pour meilleures performances
frequency: 0.005, frequency: 0.005,
opacity: 1, opacity: 1,
color: { color: {
@ -104,7 +109,7 @@ export const ParticlesBackground = () => {
} }
}, },
particles: { particles: {
enable: true, enable: false, // Désactiver le scintillement pour meilleures performances
frequency: 0.05, frequency: 0.05,
opacity: 1, opacity: 1,
color: { color: {

View File

@ -1,16 +1,18 @@
import { useEffect } from "react"; import { useEffect, lazy, Suspense } from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { Header } from "@/components/Header"; import { Header } from "@/components/Header";
import { Footer } from "@/components/Footer"; import { Footer } from "@/components/Footer";
import { ScrollProgress } from "@/components/ScrollProgress"; import { ScrollProgress } from "@/components/ScrollProgress";
import { CookieBanner } from "@/components/CookieBanner"; import { CookieBanner } from "@/components/CookieBanner";
import { HeroSection } from "@/components/sections/HeroSection"; import { HeroSection } from "@/components/sections/HeroSection";
import { ProjectsSection } from "@/components/sections/ProjectsSection";
import { SkillsSection } from "@/components/sections/SkillsSection";
import { ContactSection } from "@/components/sections/ContactSection";
import { LanguageProvider } from "@/contexts/LanguageContext"; import { LanguageProvider } from "@/contexts/LanguageContext";
import { CookieBannerProvider } from "@/contexts/CookieBannerContext"; import { CookieBannerProvider } from "@/contexts/CookieBannerContext";
// Lazy load des sections non critiques
const ProjectsSection = lazy(() => import("@/components/sections/ProjectsSection").then(module => ({ default: module.ProjectsSection })));
const SkillsSection = lazy(() => import("@/components/sections/SkillsSection").then(module => ({ default: module.SkillsSection })));
const ContactSection = lazy(() => import("@/components/sections/ContactSection").then(module => ({ default: module.ContactSection })));
const Index = () => { const Index = () => {
const location = useLocation(); const location = useLocation();
@ -34,9 +36,15 @@ const Index = () => {
<Header /> <Header />
<main> <main>
<HeroSection /> <HeroSection />
<ProjectsSection /> <Suspense fallback={<div className="py-20 md:py-32" />}>
<SkillsSection /> <ProjectsSection />
<ContactSection /> </Suspense>
<Suspense fallback={<div className="py-20 md:py-32" />}>
<SkillsSection />
</Suspense>
<Suspense fallback={<div className="py-20 md:py-32" />}>
<ContactSection />
</Suspense>
</main> </main>
<Footer /> <Footer />
<CookieBanner /> <CookieBanner />

View File

@ -103,9 +103,40 @@ const ProjectPageContent = () => {
<h2 className="text-3xl md:text-4xl font-bold mb-6"> <h2 className="text-3xl md:text-4xl font-bold mb-6">
{t("project.description") || "Description"} {t("project.description") || "Description"}
</h2> </h2>
<p className="text-lg text-muted-foreground leading-relaxed mb-12"> <p className="text-lg text-muted-foreground leading-relaxed mb-6">
{project.detailedDescription[language]} {project.detailedDescription[language]}
</p> </p>
{/* Liens intégrés dans la description */}
{(project.githubUrl || project.demoUrl) && (
<div className="flex flex-wrap gap-3 mb-12">
{project.githubUrl && (
<Button
variant="outline"
size="sm"
asChild
className="gap-2"
>
<a href={project.githubUrl} target="_blank" rel="noopener noreferrer">
<Github className="w-4 h-4" />
{t("project.viewGithub") || "View on GitHub"}
</a>
</Button>
)}
{project.demoUrl && (
<Button
size="sm"
asChild
className="gap-2"
>
<a href={project.demoUrl} target="_blank" rel="noopener noreferrer">
<ExternalLink className="w-4 h-4" />
{t("project.viewDemo") || "View Live Demo"}
</a>
</Button>
)}
</div>
)}
</motion.div> </motion.div>
<div className="grid md:grid-cols-2 gap-8"> <div className="grid md:grid-cols-2 gap-8">
@ -198,54 +229,8 @@ const ProjectPageContent = () => {
</section> </section>
)} )}
{/* Links Section */}
{(project.githubUrl || project.demoUrl) && (
<section className="py-20 bg-muted/30">
<div className="container mx-auto px-4">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="max-w-4xl mx-auto text-center"
>
<h2 className="text-3xl md:text-4xl font-bold mb-8">
{t("project.links") || "Project Links"}
</h2>
<div className="flex flex-wrap gap-4 justify-center">
{project.githubUrl && (
<Button
variant="outline"
size="lg"
asChild
className="gap-2"
>
<a href={project.githubUrl} target="_blank" rel="noopener noreferrer">
<Github className="w-5 h-5" />
{t("project.viewGithub") || "View on GitHub"}
</a>
</Button>
)}
{project.demoUrl && (
<Button
size="lg"
asChild
className="gap-2"
>
<a href={project.demoUrl} target="_blank" rel="noopener noreferrer">
<ExternalLink className="w-5 h-5" />
{t("project.viewDemo") || "View Live Demo"}
</a>
</Button>
)}
</div>
</motion.div>
</div>
</section>
)}
{/* CTA Section */} {/* CTA Section */}
<section className="py-20"> <section className="py-20 bg-muted/30">
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<motion.div <motion.div
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}