responsive4

This commit is contained in:
Ladebeze66 2025-02-19 18:11:19 +01:00
parent 6d2e96ec5f
commit a18f399ca8
9 changed files with 123 additions and 83 deletions

View File

@ -4,6 +4,8 @@ import { useEffect, useState } from "react";
import Link from "next/link"; import Link from "next/link";
import { getApiUrl } from "../utils/getApiUrl"; import { getApiUrl } from "../utils/getApiUrl";
import CarouselCompetences from "../components/CarouselCompetences"; import CarouselCompetences from "../components/CarouselCompetences";
import "../globals.css";
import "../assets/main.css";
export default function Page() { export default function Page() {
const [competences, setCompetences] = useState([]); const [competences, setCompetences] = useState([]);
@ -16,15 +18,23 @@ export default function Page() {
if (!response.ok) { if (!response.ok) {
throw new Error(`Erreur de récupération des compétences : ${response.statusText}`); throw new Error(`Erreur de récupération des compétences : ${response.statusText}`);
} }
const data = await response.json(); const data = await response.json();
setCompetences(data.data ?? []);
// Tri sécurisé des compétences par `order`
const sortedCompetences = (data.data ?? []).sort((a, b) => ((a.attributes?.order ?? 999) - (b.attributes?.order ?? 999)));
setCompetences(sortedCompetences);
} catch (error) { } catch (error) {
console.error("❌ Erreur lors de la récupération des compétences :", error); console.error("❌ Erreur lors de la récupération des compétences :", error);
} }
} }
fetchCompetences(); fetchCompetences();
}, [apiUrl]); }, [apiUrl]);
return ( return (
<main className="w-full p-3 mt-5 mb-5"> <main className="w-full p-3 mt-5 mb-5">
@ -43,21 +53,21 @@ export default function Page() {
return ( return (
<div <div
key={competence.id} key={competence.id}
className="bg-white/70 rounded-lg shadow-md overflow-hidden w-full h-auto flex flex-col transform transition-all duration-300 hover:scale-105 hover:shadow-xl p-4" className="bg-white/70 rounded-lg shadow-md overflow-hidden w-full max-w-xs sm:max-w-md md:max-w-lg lg:max-w-xl xl:max-w-2xl h-auto flex flex-col transform transition-all duration-300 hover:scale-105 hover:shadow-xl p-4"
> >
<Link href={`/competences/${competence.slug}`}> <Link href={`/competences/${competence.slug}`}>
<div className="overflow-hidden w-full h-64 mb-4"> <div className="overflow-hidden w-full h-64 mb-4">
<CarouselCompetences images={images} className="w-full h-full object-cover" /> <CarouselCompetences images={images} className="w-full h-full object-cover" />
</div> </div>
<div className="flex-grow overflow-y-auto max-h-32 hide-scrollbar show-scrollbar"> <div className="flex-grow overflow-y-auto max-h-32 hide-scrollbar show-scrollbar">
<p className="font-orbitron-16-bold text-xl mb-2">{competence.name}</p> <p className="font-orbitron-16-bold text-xl mb-2">{competence.name}</p>
<p className="text-gray-700 text-sm hover:text-base transition-all duration-200 ease-in-out"> <p className="text-gray-700 text-sm hover:text-base transition-all duration-200 ease-in-out">
{competence.description} {competence.description}
</p> </p>
</div> </div>
</Link> </Link>
</div> </div>
); );
})} })}
</div> </div>

View File

@ -88,25 +88,6 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
.bg-wallpaper {
background-image: url('./images/wallpapersite_resultat.webp');
background-size: cover;
background-position: center center;
background-repeat: no-repeat;
min-height: 100vh;
width: 100%;
}
@media (max-width: 768px) {
.bg-wallpaper {
background-size: auto 100%;
background-position: center;
min-height: 100vh;
min-width: 200vw;
}
}
.homepage-content { .homepage-content {
min-height: 50vh; min-height: 50vh;
max-height: 80vh; max-height: 80vh;
@ -179,3 +160,10 @@
.show-scrollbar:hover::-webkit-scrollbar { .show-scrollbar:hover::-webkit-scrollbar {
display: block; display: block;
} }
@media (max-width: 767px) and (orientation: landscape) {
.mobile-landscape {
grid-template-columns: repeat(2, minmax(150px, 1fr)) !important;
}
}

View File

@ -7,6 +7,8 @@ import { Navigation, Pagination, Autoplay } from "swiper/modules";
import "swiper/css"; import "swiper/css";
import "swiper/css/navigation"; import "swiper/css/navigation";
import "swiper/css/pagination"; import "swiper/css/pagination";
import "../globals.css";
import "../assets/main.css";
interface CarouselProps { interface CarouselProps {
images: Array<{ url: string; alt: string }>; images: Array<{ url: string; alt: string }>;

View File

@ -7,6 +7,8 @@ import { Navigation, Pagination, Autoplay } from "swiper/modules";
import "swiper/css"; import "swiper/css";
import "swiper/css/navigation"; import "swiper/css/navigation";
import "swiper/css/pagination"; import "swiper/css/pagination";
import "../globals.css";
import "../assets/main.css";
interface CarouselProps { interface CarouselProps {
images: Array<{ url: string; alt: string }>; images: Array<{ url: string; alt: string }>;

View File

@ -54,11 +54,38 @@ body {
animation: blink 1s infinite 0.4s; animation: blink 1s infinite 0.4s;
} }
/* Alignement général pour la mise en page */ .bg-wallpaper {
background-image: url('./assets/images/wallpapersite_resultat.webp');
background-size: cover;
background-position: center center;
background-repeat: no-repeat;
min-height: 100vh;
min-width: 100vw;
width: 100%;
height: 100%;
}
@media (max-width: 768px) {
.bg-wallpaper {
background-size: cover; /* Ajuste pour que limage soit totalement visible */
background-position: center;
width: 100vw;
min-height: 100vh;
height: auto;
}
}
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.container { .container {
max-width: 1200px; width: 100%;
margin: 0 auto; height: 100%;
padding: 16px; position: relative;
} }
/* Gestion du footer */ /* Gestion du footer */

View File

@ -3,6 +3,7 @@
import React, { useEffect, useState, useRef } from "react"; import React, { useEffect, useState, useRef } from "react";
import Footer from "./components/Footer"; import Footer from "./components/Footer";
import "./assets/main.css"; import "./assets/main.css";
import "./globals.css";
import NavLink from "./components/NavLink"; import NavLink from "./components/NavLink";
export default function RootLayout({ children }) { export default function RootLayout({ children }) {
@ -64,7 +65,7 @@ export default function RootLayout({ children }) {
{/* Menu mobile */} {/* Menu mobile */}
{isMenuOpen && ( {isMenuOpen && (
<div ref={menuRef} className="fixed inset-0 bg-black/50 z-40 flex items-start justify-center p-4"> <div ref={menuRef} className="fixed inset-0 bg-black/50 z-40 flex items-start justify-end p-4">
<nav className="w-[60%] max-w-sm h-auto min-h-[50vh] max-h-[50vh] bg-gray-800/90 backdrop-blur-lg flex flex-col items-center justify-center space-y-4 z-50 md:hidden text-white font-orbitron-24-bold tracking-wide shadow-lg overflow-y-auto rounded-lg p-6"> <nav className="w-[60%] max-w-sm h-auto min-h-[50vh] max-h-[50vh] bg-gray-800/90 backdrop-blur-lg flex flex-col items-center justify-center space-y-4 z-50 md:hidden text-white font-orbitron-24-bold tracking-wide shadow-lg overflow-y-auto rounded-lg p-6">
{/* Bouton de fermeture */} {/* Bouton de fermeture */}
<button className="absolute top-4 right-4 text-2xl text-white" onClick={toggleMenu}> <button className="absolute top-4 right-4 text-2xl text-white" onClick={toggleMenu}>

View File

@ -35,7 +35,7 @@ export default function HomePage() {
const imageUrl = homepage.photo?.url ? `${apiUrl}${homepage.photo.url}` : null; const imageUrl = homepage.photo?.url ? `${apiUrl}${homepage.photo.url}` : null;
return ( return (
<main className="max-w-3xl w-full mx-auto flex flex-col items-center justify-center p-6 bg-white/55 rounded-lg mt-12 mb-3"> <main className="w-full mx-auto flex flex-col items-center justify-center p-6 bg-white/55 rounded-lg mt-12 mb-3 max-w-7xl">
<h1 className="text-3xl font-orbitron-24-bold-italic text-gray-800 mb-4">{title}</h1> <h1 className="text-3xl font-orbitron-24-bold-italic text-gray-800 mb-4">{title}</h1>
{imageUrl ? ( {imageUrl ? (
@ -53,4 +53,4 @@ export default function HomePage() {
</div> </div>
</main> </main>
); );
} }

View File

@ -4,6 +4,8 @@ import { useEffect, useState } from "react";
import Link from "next/link"; import Link from "next/link";
import { getApiUrl } from "../utils/getApiUrl"; import { getApiUrl } from "../utils/getApiUrl";
import Carousel from "../components/Carousel"; import Carousel from "../components/Carousel";
import "../assets/main.css";
import "../globals.css";
export default function Page() { export default function Page() {
const [projects, setProjects] = useState([]); const [projects, setProjects] = useState([]);
@ -12,60 +14,65 @@ export default function Page() {
useEffect(() => { useEffect(() => {
async function fetchProjects() { async function fetchProjects() {
try { try {
const response = await fetch(`${apiUrl}/api/projects?populate=picture`); const response = await fetch(`${apiUrl}/api/projects?populate=picture&sort=order:asc`); // Récupération triée depuis Strapi
if (!response.ok) { if (!response.ok) {
throw new Error(`Erreur de récupération des projets : ${response.statusText}`); throw new Error(`Erreur de récupération des projets : ${response.statusText}`);
} }
const data = await response.json(); const data = await response.json();
setProjects(data.data ?? []);
// Tri des projets côté Next.js (au cas où Strapi ne le fait pas)
const sortedProjects = (data.data ?? []).sort((a, b) => (a.order || 999) - (b.order || 999));
setProjects(sortedProjects);
} catch (error) { } catch (error) {
console.error("❌ Erreur lors de la récupération des projets :", error); console.error("❌ Erreur lors de la récupération des projets :", error);
} }
} }
fetchProjects(); fetchProjects();
}, [apiUrl]); }, [apiUrl]);
return ( return (
<main className="w-full p-3 mt-5 mb-5"> <main className="w-full p-3 mt-5 mb-5">
<div className="grid grid-cols-1 sm:grid-cols-[repeat(auto-fit,minmax(300px,1fr))] gap-7 max-w-7xl mx-auto mobile-landscape">
<div className="grid gap-7 grid-cols-[repeat(auto-fit,minmax(300px,1fr))] max-w-7xl mx-auto"> {projects.map((project) => {
{projects.map((project) => { const pictures = project.picture ?? [];
const pictures = project.picture ?? []; const images = pictures.map((img) => ({
const images = pictures.map((img) => ({ url: `${apiUrl}${img.url}`,
url: `${apiUrl}${img.url}`, alt: img.name || "Project image",
alt: img.name || "Project image", }));
}));
return ( return (
<div <div
key={project.id} key={project.id}
className="bg-white/80 rounded-lg shadow-md overflow-hidden w-80 h-96 flex flex-col transform transition-all duration-300 hover:scale-105 hover:shadow-xl p-4" className="bg-white/80 rounded-lg shadow-md overflow-hidden w-80 h-96 flex flex-col transform transition-all duration-300 hover:scale-105 hover:shadow-xl p-4"
> >
<Link href={`/portfolio/${project.slug}`}> <Link href={`/portfolio/${project.slug}`}>
<div className="overflow-hidden w-full h-48 mb-4"> <div className="overflow-hidden w-full h-48 mb-4">
{images.length > 1 ? ( {images.length > 1 ? (
<Carousel images={images} className="h-48" /> <Carousel images={images} className="h-48" />
) : ( ) : (
<img <img
src={images[0]?.url || "/placeholder.jpg"} src={images[0]?.url || "/placeholder.jpg"}
alt={images[0]?.alt || "Project image"} alt={images[0]?.alt || "Project image"}
className="w-full h-full object-cover" className="w-full h-full object-cover"
/> />
)} )}
</div>
<div className="flex-grow overflow-y-auto max-h-32 hide-scrollbar show-scrollbar">
<p className="font-orbitron-16-bold text-xl mb-2">{project.name}</p>
<p className="text-gray-700 text-sm font-orbitron-12 hover:text-base transition-all duration-200 ease-in-out">
{project.description}
</p>
</div>
</Link>
</div> </div>
);
})} <div className="flex-grow overflow-y-auto max-h-32 hide-scrollbar show-scrollbar">
</div> <p className="font-orbitron-16-bold text-xl mb-2">{project.name}</p>
</main> <p className="text-gray-700 text-sm font-orbitron-12 hover:text-base transition-all duration-200 ease-in-out">
{project.description}
</p>
</div>
</Link>
</div>
);
})}
</div>
</main>
); );
} }

View File

@ -12,6 +12,9 @@ export default {
background: "var(--background)", background: "var(--background)",
foreground: "var(--foreground)", foreground: "var(--foreground)",
}, },
screens: {
'mobile-landscape': { 'raw': '(max-width: 767px) and (orientation: landscape)' },
},
fontFamily: { fontFamily: {
sans: ['Helvetica', 'Arial', 'sans-serif'], sans: ['Helvetica', 'Arial', 'sans-serif'],
serif: ['Georgia', 'serif'], serif: ['Georgia', 'serif'],