WIP - Big refactoring
This commit is contained in:
parent
818833d0e6
commit
463b519346
@ -10,7 +10,7 @@
|
|||||||
<!-- Ajout des polices Google Fonts -->
|
<!-- Ajout des polices Google Fonts -->
|
||||||
<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=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Dela+Gothic+One&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,528 +1,80 @@
|
|||||||
import { FiUser, FiDatabase, FiShield, FiChevronDown } from 'react-icons/fi'
|
import React, { useState } from 'react';
|
||||||
import { FaDiscord, FaArrowRight, FaEnvelope, FaGithub, FaNetworkWired, FaServer, FaLaptopCode, FaCloudUploadAlt, FaExternalLinkAlt } from 'react-icons/fa'
|
import { Navigation } from './components/layout/Navigation';
|
||||||
import { FiX, FiExternalLink } from 'react-icons/fi'
|
import { Footer } from './components/layout/Footer';
|
||||||
import './App.css'
|
import { HeroSection } from './components/sections/HeroSection';
|
||||||
import icebergImage from './assets/iceberg.png'
|
import { TechFeaturesSection } from './components/sections/TechFeaturesSection';
|
||||||
import logoImage from './assets/banquise_server.svg'
|
import { ServicesSection } from './components/sections/ServicesSection';
|
||||||
import { useEffect, useState, useMemo, useCallback, useRef } from 'react'
|
import { AboutSection } from './components/sections/AboutSection';
|
||||||
|
import { Popup } from './components/ui/Popup';
|
||||||
|
|
||||||
import aboutImage from './assets/banquise.png'
|
// Define Service interface directly in App
|
||||||
|
interface Service {
|
||||||
function App() {
|
name: string;
|
||||||
const [selectedService, setSelectedService] = useState<number | null>(null);
|
url: string;
|
||||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
image: string;
|
||||||
const mobileMenuRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const services = useMemo(() => [
|
|
||||||
{
|
|
||||||
name: "Wiki",
|
|
||||||
url: "https://wiki.la-banquise.fr/",
|
|
||||||
description: "Une instance de wikijs, ou nous essayons de documenter nos projets, nos services ou encore notre infra, et aussi des petits tutoriels pour bien comprendre les outils utilises a EPITA !"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Git",
|
|
||||||
url: "https://git.la-banquise.fr/",
|
|
||||||
description: "Gitea est notre plateforme de gestion de code source, similaire à GitHub, hébergée par nos soins. Nos divers projets necessitant Git, comme par exemple ce site, sont heberges et développes grace a cet outil."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Panel jeux",
|
|
||||||
url: "https://panel.la-banquise.fr/auth/login",
|
|
||||||
description: "Interface de connection à notre panel Pterodactyl, qui vous permet de gérer vos serveurs de jeux. Celui ci sera remplace dans l ete par pelican."
|
|
||||||
},
|
|
||||||
], []);
|
|
||||||
|
|
||||||
const [icebergs, setIcebergs] = useState<Array<{
|
|
||||||
id: number,
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
scale: number,
|
|
||||||
rotation: number,
|
|
||||||
service: typeof services[0],
|
|
||||||
floatClass: string
|
|
||||||
}>>([])
|
|
||||||
|
|
||||||
const [reducedMotion, setReducedMotion] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
||||||
setReducedMotion(prefersReducedMotion);
|
|
||||||
|
|
||||||
const startTime = performance.now();
|
|
||||||
let count = 0;
|
|
||||||
while (performance.now() - startTime < 5) {
|
|
||||||
count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count < 1000) {
|
const App: React.FC = () => {
|
||||||
setReducedMotion(true);
|
// Define services directly in the component
|
||||||
}
|
const services: Service[] = [
|
||||||
}, []);
|
{ name: "Wiki", url: "https://wiki.labanquise.org", image: "/src/assets/iceberg.png" },
|
||||||
|
{ name: "Gitea", url: "https://git.labanquise.org", image: "/src/assets/iceberg.png" },
|
||||||
const positionIcebergs = useCallback(() => {
|
{ name: "Panel", url: "https://panel.labanquise.org", image: "/src/assets/iceberg.png" }
|
||||||
const newIcebergs = [];
|
|
||||||
|
|
||||||
const positions = [
|
|
||||||
{ x: 25, y: 35, scale: 0.95, rotation: 0 },
|
|
||||||
{ x: 50, y: 25, scale: 1.1, rotation: 0 },
|
|
||||||
{ x: 75, y: 35, scale: 0.95, rotation: 0 },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const floatClasses = ['float-1', 'float-2', 'float-3', 'float-4', 'float-5'];
|
const [selectedService, setSelectedService] = useState<Service | null>(null);
|
||||||
|
|
||||||
for (let i = 0; i < services.length; i++) {
|
// Inline accordion logic
|
||||||
const position = positions[i % positions.length];
|
const [openAccordion, setOpenAccordion] = useState<string | null>(null);
|
||||||
|
const toggleAccordion = (title: string) => {
|
||||||
newIcebergs.push({
|
setOpenAccordion(openAccordion === title ? null : title);
|
||||||
id: i,
|
|
||||||
x: position.x,
|
|
||||||
y: position.y,
|
|
||||||
scale: position.scale,
|
|
||||||
rotation: position.rotation,
|
|
||||||
service: services[i],
|
|
||||||
floatClass: reducedMotion ? '' : floatClasses[i % floatClasses.length]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return newIcebergs;
|
|
||||||
}, [services, reducedMotion]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setIcebergs(positionIcebergs());
|
|
||||||
}, [positionIcebergs]);
|
|
||||||
|
|
||||||
const renderBubbles = useMemo(() => {
|
|
||||||
if (reducedMotion) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="bubbles">
|
|
||||||
<div className="bubble"></div>
|
|
||||||
<div className="bubble"></div>
|
|
||||||
<div className="bubble"></div>
|
|
||||||
<div className="bubble"></div>
|
|
||||||
<div className="bubble"></div>
|
|
||||||
<div className="bubble"></div>
|
|
||||||
<div className="bubble"></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}, [reducedMotion]);
|
|
||||||
|
|
||||||
const handleIcebergClick = (event: React.MouseEvent, serviceId: number) => {
|
|
||||||
event.preventDefault();
|
|
||||||
setSelectedService(serviceId);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClosePopup = () => {
|
|
||||||
setSelectedService(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleOutsideClick = (event: MouseEvent) => {
|
|
||||||
if (mobileMenuRef.current && !mobileMenuRef.current.contains(event.target as Node)) {
|
|
||||||
setMobileMenuOpen(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (mobileMenuOpen) {
|
|
||||||
document.addEventListener('mousedown', handleOutsideClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener('mousedown', handleOutsideClick);
|
|
||||||
};
|
|
||||||
}, [mobileMenuOpen]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (mobileMenuOpen) {
|
|
||||||
document.body.style.overflow = 'hidden';
|
|
||||||
} else {
|
|
||||||
document.body.style.overflow = 'auto';
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
document.body.style.overflow = 'auto';
|
|
||||||
};
|
|
||||||
}, [mobileMenuOpen]);
|
|
||||||
|
|
||||||
const [activeAccordion, setActiveAccordion] = useState<number | null>(null);
|
|
||||||
|
|
||||||
// FAQ items for the about section
|
|
||||||
const faqItems = useMemo(() => [
|
|
||||||
{
|
|
||||||
question: "Qui sommes-nous ?",
|
|
||||||
answer: (
|
|
||||||
<>
|
|
||||||
<p>La Banquise est une association étudiante de l'EPITA, dont l'objectif est de former les epiteens a diverses notions de reseau et d'hebergement de servcies.
|
|
||||||
Fondée a la rentree 2022, notre asso permet à ceux qui le souhaitent de se former sur des technologies d'hébergement et de réseau, sur nos serveurs, a dispositon des etudiants.</p>
|
|
||||||
<p>Notre équipe est composée d'étudiants passionnés par l'informatique, le réseau et le partage de connaissances. Nous mettons notre expertise au service des étudiants et des associations de l'EPITA.</p>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Comment candidater pour rejoindre La Banquise ?",
|
|
||||||
answer: (
|
|
||||||
<>
|
|
||||||
<p>Pour rejoindre notre équipe, rien de plus simple :</p>
|
|
||||||
<ul>
|
|
||||||
<li>Rejoignez notre serveur Discord</li>
|
|
||||||
<li>Donnez votre login EPITA dans un ticket, ou expliquer ce dont vous avez besoin si vous n etes pas d'EPITA</li>
|
|
||||||
<li>Un moderateur vous mettra le role necessaire pour acceder au salons avec tout nos projets sur discord !</li>
|
|
||||||
</ul>
|
|
||||||
<p>Si vous etes motivé.e, peu importe votre niveau technique actuel, n'hesitez pas a venir nous poser des question ou venir demander des ressources pour un projet !</p>
|
|
||||||
<a href="https://discord.com/invite/QQWwzX5ptY" className="accordion-cta" target="_blank" rel="noopener noreferrer">
|
|
||||||
Rejoindre notre Discord <FaExternalLinkAlt className="accordion-cta-icon" />
|
|
||||||
</a>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Quels sont nos objectifs ?",
|
|
||||||
answer: (
|
|
||||||
<>
|
|
||||||
<p>Nos principaux objectifs sont :</p>
|
|
||||||
<ul>
|
|
||||||
<li>Former les étudiants aux technologies d'hébergement et de réseau</li>
|
|
||||||
<li>Fournir des services informatiques de qualité aux étudiants et associations de l'EPITA</li>
|
|
||||||
<li>Promouvoir le partage de connaissances et l'entraide</li>
|
|
||||||
<li>Créer un environnement d'apprentissage pratique par l'expérience</li>
|
|
||||||
<li>Maintenir une infrastructure robuste et sécurisée</li>
|
|
||||||
</ul>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Comment utiliser nos services ?",
|
|
||||||
answer: (
|
|
||||||
<>
|
|
||||||
<p>Pour accéder à nos services :</p>
|
|
||||||
<ol>
|
|
||||||
<li>Connectez-vous au service souhaité avec vos identifiants, pour le moment crees par un admin</li>
|
|
||||||
<li>Consultez notre Wiki pour obtenir de l'aide sur l'utilisation de chaque service !</li>
|
|
||||||
</ol>
|
|
||||||
<p>Si vous rencontrez des difficultés, n'hésitez pas à demander de l'aide sur notre Discord.</p>
|
|
||||||
<a href="https://auth.la-banquise.fr/" className="accordion-cta" target="_blank" rel="noopener noreferrer">
|
|
||||||
Se Connecter <FaExternalLinkAlt className="accordion-cta-icon" />
|
|
||||||
</a>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Comment contribuer a un projet ?",
|
|
||||||
answer: (
|
|
||||||
<>
|
|
||||||
<p>Il existe plusieurs façons de contribuer aux projets La Banquise :</p>
|
|
||||||
<ul>
|
|
||||||
<li>Deployer des services</li>
|
|
||||||
<li>Experimenter et documenter le fonctionnement de technologies (k8s, openstack...)</li>
|
|
||||||
<li>Aider a gerer les ressources de l'asso</li>
|
|
||||||
<li>Contribuer au code source de nos projets via Gitea</li>
|
|
||||||
<li>Rédiger ou améliorer la documentation sur notre Wiki</li>
|
|
||||||
<li>Proposer de nouvelles idées de services ou d'améliorations</li>
|
|
||||||
<li>Aider d'autres utilisateurs sur notre Discord</li>
|
|
||||||
</ul>
|
|
||||||
<p>Toutes les contributions sont les bienvenues, même les plus modestes !</p>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
], []);
|
|
||||||
|
|
||||||
const toggleAccordion = (index: number) => {
|
|
||||||
setActiveAccordion(activeAccordion === index ? null : index);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="app-container">
|
<div className="flex flex-col min-h-screen w-full">
|
||||||
<a href="#main-content" className="sr-only focus:not-sr-only">Passer au contenu principal</a>
|
<Navigation />
|
||||||
|
|
||||||
<header>
|
<main className="flex-1 flex flex-col overflow-x-hidden overflow-y-auto">
|
||||||
<nav className="navbar" aria-label="Navigation principale">
|
<div className="relative flex-1 bg-ocean-gradient w-full min-h-[calc(100vh-72px)] flex flex-col justify-start items-center overflow-x-hidden">
|
||||||
<div className="navbar-left">
|
|
||||||
<img src={logoImage} alt="Logo La Banquise" className="site-logo" />
|
<HeroSection />
|
||||||
<h1 className="site-name">La Banquise</h1>
|
<TechFeaturesSection />
|
||||||
|
<ServicesSection services={services} onServiceClick={setSelectedService} />
|
||||||
|
<AboutSection openAccordion={openAccordion} toggleAccordion={toggleAccordion} />
|
||||||
|
|
||||||
|
{/* Waves effect */}
|
||||||
|
<div className="absolute bottom-0 left-0 w-full h-52 overflow-hidden z-1 pointer-events-none">
|
||||||
|
<div className="absolute bottom-0 left-0 w-full h-28 bg-wave-pattern bg-repeat-x opacity-30 animate-wave-1 z-1" style={{ backgroundSize: '1200px 100px' }}></div>
|
||||||
|
<div className="absolute -bottom-3 left-0 w-full h-28 bg-wave-pattern bg-repeat-x opacity-50 animate-wave-2 z-2" style={{ backgroundSize: '1200px 100px', animationDelay: '-5s' }}></div>
|
||||||
|
<div className="absolute -bottom-5 left-0 w-full h-28 bg-wave-pattern bg-repeat-x opacity-70 animate-wave-3 z-3" style={{ backgroundSize: '1200px 100px', animationDelay: '-2s' }}></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
{/* Bubbles effect */}
|
||||||
className={`navbar-mobile-toggle ${mobileMenuOpen ? 'active' : ''}`}
|
<div className="absolute w-full h-full overflow-hidden top-0 left-0 z-1 pointer-events-none">
|
||||||
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
{[...Array(7)].map((_, i) => (
|
||||||
aria-expanded={mobileMenuOpen}
|
|
||||||
aria-label="Menu de navigation"
|
|
||||||
>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`navbar-right ${mobileMenuOpen ? 'mobile-active' : ''}`}
|
key={i}
|
||||||
ref={mobileMenuRef}
|
className={`absolute -bottom-5 rounded-full bg-banquise-blue-lightest/20 opacity-80 animate-rise`}
|
||||||
>
|
|
||||||
<a
|
|
||||||
href="https://discord.com/invite/QQWwzX5ptY"
|
|
||||||
className="discord-button"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
aria-label="Rejoindre notre Discord"
|
|
||||||
onClick={() => setMobileMenuOpen(false)}
|
|
||||||
>
|
|
||||||
<FaDiscord className="discord-icon" aria-hidden="true" />
|
|
||||||
<span>Discord</span>
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="https://auth.la-banquise.fr/"
|
|
||||||
className="login-button"
|
|
||||||
aria-label="Se connecter à votre compte"
|
|
||||||
onClick={() => setMobileMenuOpen(false)}
|
|
||||||
>
|
|
||||||
<FiUser className="login-icon" aria-hidden="true" />
|
|
||||||
<span>Se connecter</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className={`mobile-menu-overlay ${mobileMenuOpen ? 'active' : ''}`}
|
|
||||||
onClick={() => setMobileMenuOpen(false)}
|
|
||||||
></div>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main id="main-content" className="content">
|
|
||||||
<div className="ocean" role="region" aria-label="Services La Banquise">
|
|
||||||
{renderBubbles}
|
|
||||||
|
|
||||||
<section className="page-section hero-section">
|
|
||||||
<div className="hero-tech-elements">
|
|
||||||
<div className="tech-element tech-element-1"><FaServer /></div>
|
|
||||||
<div className="tech-element tech-element-2"><FaLaptopCode /></div>
|
|
||||||
<div className="tech-element tech-element-3"><FaNetworkWired /></div>
|
|
||||||
<div className="tech-element tech-element-4"><FaCloudUploadAlt /></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="hero-logo-container">
|
|
||||||
<img src={logoImage} alt="Logo La Banquise" className="hero-logo" />
|
|
||||||
</div>
|
|
||||||
<h2 className="hero-title">Association La Banquise</h2>
|
|
||||||
<p className="hero-subtitle">
|
|
||||||
Association d'hébergement et lab réseau pour tous les étudiants et associations de l'EPITA !
|
|
||||||
</p>
|
|
||||||
<div>
|
|
||||||
<a href="https://discord.com/invite/QQWwzX5ptY" className="cta-button" target="_blank" rel="noopener noreferrer">
|
|
||||||
Notre Discord
|
|
||||||
<FaArrowRight className="cta-icon" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="page-section tech-features-section">
|
|
||||||
<div className="section-divider"></div>
|
|
||||||
<h2 className="section-title">Notre infrastructure</h2>
|
|
||||||
<p className="section-subtitle">
|
|
||||||
25+ serveurs pour répondre à vos besoins
|
|
||||||
</p>
|
|
||||||
<p className="section-subtitle">
|
|
||||||
Un local a EPITA Lyon, prochainement a Paris ?
|
|
||||||
</p>
|
|
||||||
<div className="tech-features-grid">
|
|
||||||
<div className="tech-feature-card">
|
|
||||||
<div className="tech-feature-icon">
|
|
||||||
<FaServer />
|
|
||||||
</div>
|
|
||||||
<h3 className="tech-feature-title">Serveurs performants</h3>
|
|
||||||
<p className="tech-feature-description">
|
|
||||||
Infrastructure optimisée pour assurer des performances élevées et une disponibilité maximale de vos applications
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="tech-feature-card">
|
|
||||||
<div className="tech-feature-icon">
|
|
||||||
<FiDatabase />
|
|
||||||
</div>
|
|
||||||
<h3 className="tech-feature-title">Stockage sécurisé</h3>
|
|
||||||
<p className="tech-feature-description">
|
|
||||||
Solutions de stockage distribuées avec redondance pour garantir l'intégrité et la durabilité de vos données
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="tech-feature-card">
|
|
||||||
<div className="tech-feature-icon">
|
|
||||||
<FaNetworkWired />
|
|
||||||
</div>
|
|
||||||
<h3 className="tech-feature-title">Réseau optimisé</h3>
|
|
||||||
<p className="tech-feature-description">
|
|
||||||
Architecture réseau à haute disponibilité avec une faible latence pour vos applications critiques
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="tech-feature-card">
|
|
||||||
<div className="tech-feature-icon">
|
|
||||||
<FiShield />
|
|
||||||
</div>
|
|
||||||
<h3 className="tech-feature-title">Sécurité renforcée</h3>
|
|
||||||
<p className="tech-feature-description">
|
|
||||||
Protection contre les menaces avec systèmes de sécurité modernes et mises à jour régulières
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="page-section services-section" id="services">
|
|
||||||
<div className="section-divider"></div>
|
|
||||||
<h2 className="section-title">Nos services</h2>
|
|
||||||
<p className="section-subtitle">
|
|
||||||
Explorez notre écosystème de services conçus pour répondre à vos besoins.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className="icebergs-container"
|
|
||||||
role="list"
|
|
||||||
aria-label="Liste des services disponibles"
|
|
||||||
>
|
|
||||||
{icebergs.map((iceberg) => (
|
|
||||||
<a
|
|
||||||
key={iceberg.id}
|
|
||||||
href={iceberg.service.url}
|
|
||||||
className={`iceberg ${iceberg.floatClass}`}
|
|
||||||
style={{
|
style={{
|
||||||
transform: `rotate(${iceberg.rotation}deg) scale(${iceberg.scale}) translateZ(0)`,
|
width: `${[25, 30, 35, 28, 22, 32, 20][i]}px`,
|
||||||
|
height: `${[25, 30, 35, 28, 22, 32, 20][i]}px`,
|
||||||
|
left: `${[10, 20, 35, 50, 65, 80, 90][i]}%`,
|
||||||
|
animationDuration: `${[8, 9, 10, 7, 12, 9, 8][i]}s`,
|
||||||
|
animationDelay: `${[0, 1, 2, 0, 3, 1.5, 2.5][i]}s`,
|
||||||
}}
|
}}
|
||||||
role="listitem"
|
></div>
|
||||||
aria-label={`En savoir plus sur ${iceberg.service.name}`}
|
|
||||||
onClick={(e) => handleIcebergClick(e, iceberg.id)}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src={icebergImage}
|
|
||||||
alt=""
|
|
||||||
className="iceberg-image"
|
|
||||||
loading="lazy"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
<div className="service-name">{iceberg.service.name}</div>
|
|
||||||
</a>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="page-section about-section" id="about">
|
|
||||||
<div className="section-divider"></div>
|
|
||||||
<h2 className="section-title">À propos de nous</h2>
|
|
||||||
<p className="section-subtitle">
|
|
||||||
Découvrez notre mission et posez-nous vos questions
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="about-container">
|
|
||||||
<div className="about-image-container">
|
|
||||||
<img src={aboutImage} alt="Logo La Banquise" className="about-logo" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p className="about-intro">
|
|
||||||
La Banquise est une association étudiante dédiée à l'hébergement de services et à la formation sur les technologies réseau, au service de la communauté EPITA.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="accordion-group" role="region" aria-label="Foire aux questions">
|
|
||||||
{faqItems.map((item, index) => (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
className={`accordion-item ${activeAccordion === index ? 'active' : ''}`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="accordion-header"
|
|
||||||
onClick={() => toggleAccordion(index)}
|
|
||||||
role="button"
|
|
||||||
aria-expanded={activeAccordion === index}
|
|
||||||
aria-controls={`accordion-content-${index}`}
|
|
||||||
tabIndex={0}
|
|
||||||
onKeyPress={(e) => {
|
|
||||||
if (e.key === 'Enter' || e.key === ' ') {
|
|
||||||
toggleAccordion(index);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.question}
|
|
||||||
<FiChevronDown className="accordion-toggle-icon" aria-hidden="true" />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="accordion-content"
|
|
||||||
id={`accordion-content-${index}`}
|
|
||||||
role="region"
|
|
||||||
>
|
|
||||||
{item.answer}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{selectedService !== null && (
|
|
||||||
<div className="popup-overlay" onClick={handleClosePopup} role="dialog" aria-modal="true" aria-labelledby="popup-title">
|
|
||||||
<div className="popup-content" onClick={(e) => e.stopPropagation()}>
|
|
||||||
<button className="popup-close" onClick={handleClosePopup} aria-label="Fermer">
|
|
||||||
<FiX />
|
|
||||||
</button>
|
|
||||||
<h3 id="popup-title" className="popup-title">{services[selectedService].name}</h3>
|
|
||||||
<p className="popup-description">{services[selectedService].description}</p>
|
|
||||||
<a
|
|
||||||
href={services[selectedService].url}
|
|
||||||
className="popup-button"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<FiExternalLink className="popup-button-icon" />
|
|
||||||
<span>Accéder au service</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="code-background">
|
|
||||||
<div className="code-line">const banquise = new ServerInfra();</div>
|
|
||||||
<div className="code-line">banquise.deploy('wiki');</div>
|
|
||||||
<div className="code-line">banquise.deploy('gitea');</div>
|
|
||||||
<div className="code-line">banquise.optimize();</div>
|
|
||||||
<div className="code-line">banquise.monitor();</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="waves" aria-hidden="true">
|
|
||||||
<div className="wave wave1"></div>
|
|
||||||
<div className="wave wave2"></div>
|
|
||||||
<div className="wave wave3"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer className="footer">
|
<Footer />
|
||||||
<div className="footer-content">
|
|
||||||
<div className="footer-column">
|
{selectedService && (
|
||||||
<h4>La Banquise</h4>
|
<Popup service={selectedService} onClose={() => setSelectedService(null)} />
|
||||||
<ul>
|
)}
|
||||||
<li><a href="#about">À propos</a></li>
|
|
||||||
<li><a href="#services">Services</a></li>
|
|
||||||
<li><a href="https://wiki.la-banquise.fr/en/home">Documentation</a></li>
|
|
||||||
<li><a href="#contact">Contact</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div className="footer-column">
|
|
||||||
<h4>Services</h4>
|
|
||||||
<ul>
|
|
||||||
{services.map((service, index) => (
|
|
||||||
<li key={index}><a href={service.url}>{service.name}</a></li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div className="footer-column">
|
|
||||||
<h4>Communauté</h4>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://discord.com/invite/QQWwzX5ptY" target="_blank" rel="noopener noreferrer">Discord</a></li>
|
|
||||||
<li><a href="https://git.la-banquise.fr/" target="_blank" rel="noopener noreferrer">Gitea</a></li>
|
|
||||||
<li><a href="mailto:contact@la-banquise.fr"><FaEnvelope style={{marginRight: '0.5rem'}} /> contact@la-banquise.fr</a></li>
|
|
||||||
<li><a href="https://github.com/la-banquise" target="_blank" rel="noopener noreferrer"><FaGithub style={{marginRight: '0.5rem'}} /> GitHub</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="footer-bottom">
|
|
||||||
<p>© {new Date().getFullYear()} La Banquise. Tous droits réservés.</p>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
65
banquise-website/src/components/layout/Footer.tsx
Normal file
65
banquise-website/src/components/layout/Footer.tsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export const Footer: React.FC = () => (
|
||||||
|
<footer className="bg-banquise-blue-dark text-white py-16 px-8 pt-16 relative z-3 border-t border-white/10 w-full box-border">
|
||||||
|
<div className="flex flex-wrap justify-between max-w-6xl mx-auto">
|
||||||
|
<div className="flex-1 min-w-64 mb-8 text-left px-6">
|
||||||
|
<h4 className="text-xl mb-6 text-banquise-blue-lightest relative pb-3 after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-10 after:h-0.5 after:bg-banquise-blue-lightest">
|
||||||
|
Services
|
||||||
|
</h4>
|
||||||
|
<ul className="list-none p-0 m-0">
|
||||||
|
<li className="mb-3">
|
||||||
|
<a href="https://wiki.labanquise.org" className="text-banquise-gray/80 no-underline transition-all duration-200 inline-flex items-center hover:text-banquise-gray hover:translate-x-1">
|
||||||
|
Wiki
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li className="mb-3">
|
||||||
|
<a href="https://git.labanquise.org" className="text-banquise-gray/80 no-underline transition-all duration-200 inline-flex items-center hover:text-banquise-gray hover:translate-x-1">
|
||||||
|
Gitea
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li className="mb-3">
|
||||||
|
<a href="https://panel.labanquise.org" className="text-banquise-gray/80 no-underline transition-all duration-200 inline-flex items-center hover:text-banquise-gray hover:translate-x-1">
|
||||||
|
Panel
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1 min-w-64 mb-8 text-left px-6">
|
||||||
|
<h4 className="text-xl mb-6 text-banquise-blue-lightest relative pb-3 after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-10 after:h-0.5 after:bg-banquise-blue-lightest">
|
||||||
|
Communauté
|
||||||
|
</h4>
|
||||||
|
<ul className="list-none p-0 m-0">
|
||||||
|
<li className="mb-3">
|
||||||
|
<a href="https://discord.gg/labanquise" className="text-banquise-gray/80 no-underline transition-all duration-200 inline-flex items-center hover:text-banquise-gray hover:translate-x-1">
|
||||||
|
Discord
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1 min-w-64 mb-8 text-left px-6">
|
||||||
|
<h4 className="text-xl mb-6 text-banquise-blue-lightest relative pb-3 after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-10 after:h-0.5 after:bg-banquise-blue-lightest">
|
||||||
|
Support
|
||||||
|
</h4>
|
||||||
|
<ul className="list-none p-0 m-0">
|
||||||
|
<li className="mb-3">
|
||||||
|
<a href="#" className="text-banquise-gray/80 no-underline transition-all duration-200 inline-flex items-center hover:text-banquise-gray hover:translate-x-1">
|
||||||
|
Documentation
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li className="mb-3">
|
||||||
|
<a href="#" className="text-banquise-gray/80 no-underline transition-all duration-200 inline-flex items-center hover:text-banquise-gray hover:translate-x-1">
|
||||||
|
Contact
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border-t border-white/10 pt-6 mt-8 text-center text-sm text-white/70 max-w-6xl mx-auto">
|
||||||
|
© 2024 La Banquise. Tous droits réservés.
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
);
|
0
banquise-website/src/components/layout/Header.tsx
Normal file
0
banquise-website/src/components/layout/Header.tsx
Normal file
42
banquise-website/src/components/layout/Navigation.tsx
Normal file
42
banquise-website/src/components/layout/Navigation.tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
export const Navigation: React.FC = () => {
|
||||||
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav className="flex justify-between items-center py-3 px-8 bg-banquise-blue-dark/95 text-white shadow-lg w-full box-border z-10 backdrop-blur-lg border-b border-white/10 sticky top-0">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<img src="/src/assets/banquise.png" alt="Logo La Banquise" className="h-9 w-auto mr-4 drop-shadow-lg" style={{ filter: 'drop-shadow(0 0 5px rgba(168, 218, 255, 0.4))' }} />
|
||||||
|
<h1 className="text-2xl font-bold m-0 text-white tracking-wide font-heading">La Banquise</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-3 md:flex hidden">
|
||||||
|
<a href="https://discord.gg/labanquise" className="flex items-center bg-banquise-blue text-white border-0 py-2 px-5 rounded-md cursor-pointer no-underline font-semibold tracking-wide shadow-lg transition-all duration-200 hover:bg-banquise-blue/80 hover:-translate-y-0.5 hover:shadow-xl hover:text-white hover:shadow-banquise-blue/60 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white">
|
||||||
|
Discord
|
||||||
|
</a>
|
||||||
|
<a href="#login" className="flex items-center bg-banquise-blue-light/90 text-white border-0 py-2 px-5 rounded-md cursor-pointer no-underline font-semibold tracking-wide shadow-lg transition-all duration-200 hover:bg-banquise-blue-light hover:-translate-y-0.5 hover:shadow-xl hover:text-white hover:shadow-banquise-blue-light/50 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white">
|
||||||
|
<span className="mr-2">👤</span>
|
||||||
|
Connexion
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="md:hidden bg-transparent border-0 cursor-pointer p-1 z-20 w-10 h-10 relative"
|
||||||
|
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||||
|
>
|
||||||
|
<span className={`block w-6 h-0.5 bg-white my-1 mx-auto transition-all duration-300 ${mobileMenuOpen ? 'translate-y-2 rotate-45' : ''}`}></span>
|
||||||
|
<span className={`block w-6 h-0.5 bg-white my-1 mx-auto transition-all duration-300 ${mobileMenuOpen ? 'opacity-0 scale-0' : ''}`}></span>
|
||||||
|
<span className={`block w-6 h-0.5 bg-white my-1 mx-auto transition-all duration-300 ${mobileMenuOpen ? '-translate-y-2 -rotate-45' : ''}`}></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Mobile menu overlay */}
|
||||||
|
<div className={`md:hidden fixed top-0 left-0 w-full h-full bg-black/50 z-14 transition-all duration-300 ${mobileMenuOpen ? 'visible opacity-100' : 'invisible opacity-0'}`} onClick={() => setMobileMenuOpen(false)}></div>
|
||||||
|
|
||||||
|
{/* Mobile menu */}
|
||||||
|
<div className={`md:hidden fixed top-0 right-0 flex-col bg-banquise-blue-dark/98 h-full w-3/5 max-w-xs pt-20 transition-all duration-300 z-15 gap-5 backdrop-blur-lg shadow-xl ${mobileMenuOpen ? 'translate-x-0 visible opacity-100' : 'translate-x-full invisible opacity-0'}`}>
|
||||||
|
<a href="https://discord.gg/labanquise" className="block p-4 text-white no-underline hover:bg-banquise-blue/20">Discord</a>
|
||||||
|
<a href="#login" className="block p-4 text-white no-underline hover:bg-banquise-blue/20">👤 Connexion</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
};
|
78
banquise-website/src/components/sections/AboutSection.tsx
Normal file
78
banquise-website/src/components/sections/AboutSection.tsx
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { AccordionItem } from '../ui/AccordionItem';
|
||||||
|
|
||||||
|
interface AboutSectionProps {
|
||||||
|
openAccordion: string | null;
|
||||||
|
toggleAccordion: (title: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AboutSection: React.FC<AboutSectionProps> = ({ openAccordion, toggleAccordion }) => (
|
||||||
|
<section className="relative bg-banquise-blue-dark/15 backdrop-blur-lg m-0 py-16 px-8 z-2 border-t border-white/10 border-b border-white/10 w-full box-border">
|
||||||
|
<div className="max-w-5xl mx-auto flex flex-col items-center w-full">
|
||||||
|
<div className="w-20 h-1 bg-gradient-to-r from-banquise-blue-lightest to-banquise-blue mx-auto mb-8 rounded-full"></div>
|
||||||
|
<h2 className="text-banquise-gray text-4xl mb-4 text-center font-heading font-bold tracking-tight" style={{ textShadow: '0 2px 4px rgba(0, 0, 0, 0.2)' }}>
|
||||||
|
À Propos
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div className="max-w-48 mx-auto mb-8 relative z-2">
|
||||||
|
<img
|
||||||
|
src="/src/assets/banquise.png"
|
||||||
|
alt="Logo La Banquise"
|
||||||
|
className="w-full h-auto rounded-full p-4 bg-white/5 border-2 border-banquise-blue-lightest/30 shadow-xl animate-gentle-float"
|
||||||
|
style={{ boxShadow: '0 10px 25px rgba(31, 93, 137, 0.3)' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-center max-w-4xl mx-auto mb-10 text-banquise-gray text-lg leading-relaxed" style={{ textShadow: '0 1px 2px rgba(0, 0, 0, 0.1)' }}>
|
||||||
|
La Banquise est une communauté passionnée qui propose des services d'hébergement et des outils collaboratifs pour les développeurs et les gamers.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-full flex flex-col gap-4 mt-6">
|
||||||
|
<AccordionItem
|
||||||
|
title="🎯 Notre Mission"
|
||||||
|
isOpen={openAccordion === "mission"}
|
||||||
|
onToggle={() => toggleAccordion("mission")}
|
||||||
|
>
|
||||||
|
<p className="mt-0 mb-4">
|
||||||
|
Fournir une plateforme stable et accessible pour héberger vos projets, partager vos connaissances et jouer ensemble.
|
||||||
|
</p>
|
||||||
|
<p className="mb-0">
|
||||||
|
Nous croyons en la puissance de la collaboration et mettons à disposition des outils modernes pour faciliter le travail en équipe.
|
||||||
|
</p>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
|
<AccordionItem
|
||||||
|
title="🛠️ Nos Services"
|
||||||
|
isOpen={openAccordion === "services"}
|
||||||
|
onToggle={() => toggleAccordion("services")}
|
||||||
|
>
|
||||||
|
<ul className="mt-2 mb-2 pl-6">
|
||||||
|
<li className="mb-2"><strong>Wiki :</strong> Documentation collaborative et guides détaillés</li>
|
||||||
|
<li className="mb-2"><strong>Gitea :</strong> Gestion de versions Git auto-hébergée</li>
|
||||||
|
<li className="mb-2"><strong>Panel de Jeux :</strong> Interface de gestion pour serveurs de jeux</li>
|
||||||
|
</ul>
|
||||||
|
<p className="mb-0">
|
||||||
|
Tous nos services sont maintenus avec soin et régulièrement mis à jour pour garantir une expérience optimale.
|
||||||
|
</p>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
|
<AccordionItem
|
||||||
|
title="🤝 Rejoindre la Communauté"
|
||||||
|
isOpen={openAccordion === "community"}
|
||||||
|
onToggle={() => toggleAccordion("community")}
|
||||||
|
>
|
||||||
|
<p className="mt-0 mb-4">
|
||||||
|
Rejoignez notre serveur Discord pour échanger avec la communauté, obtenir de l'aide et rester informé des dernières nouveautés.
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
href="https://discord.gg/labanquise"
|
||||||
|
className="inline-flex items-center bg-banquise-blue text-white border-0 py-3 px-5 rounded-md mt-4 no-underline font-semibold transition-all duration-200 hover:bg-banquise-blue/80 hover:-translate-y-1 hover:shadow-lg"
|
||||||
|
>
|
||||||
|
<span className="mr-2 text-sm">💬</span>
|
||||||
|
Rejoindre Discord
|
||||||
|
</a>
|
||||||
|
</AccordionItem>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
30
banquise-website/src/components/sections/HeroSection.tsx
Normal file
30
banquise-website/src/components/sections/HeroSection.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export const HeroSection: React.FC = () => (
|
||||||
|
<section className="min-h-[calc(70vh-72px)] flex flex-col justify-center items-center text-center pt-12 pb-12 mt-0 w-full max-w-6xl mx-auto px-8 relative z-3">
|
||||||
|
<div className="mb-8 w-40 h-40 rounded-full bg-white/10 p-4 shadow-2xl animate-gentle-float">
|
||||||
|
<img src="/src/assets/banquise.png" alt="Logo La Banquise" className="w-full h-full object-contain" style={{ filter: 'drop-shadow(0 5px 15px rgba(0, 0, 0, 0.2))' }} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 className="text-banquise-gray text-6xl mb-6 font-extrabold leading-tight max-w-4xl font-heading" style={{ textShadow: '0 2px 10px rgba(0, 0, 0, 0.3)' }}>
|
||||||
|
Bienvenue sur La Banquise
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p className="text-banquise-gray text-2xl mb-10 max-w-3xl font-normal opacity-90" style={{ textShadow: '0 1px 4px rgba(0, 0, 0, 0.2)' }}>
|
||||||
|
Votre plateforme d'hébergement communautaire
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="#services" className="inline-flex items-center justify-center bg-banquise-gray text-banquise-blue-dark border-0 py-4 px-10 rounded-full text-lg font-semibold no-underline shadow-lg transition-all duration-300 min-w-52 hover:-translate-y-1 hover:shadow-xl hover:bg-white">
|
||||||
|
Découvrir nos services
|
||||||
|
<span className="ml-3 transition-transform duration-200 hover:translate-x-1">→</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{/* Tech elements background */}
|
||||||
|
<div className="absolute top-0 left-0 w-full h-full pointer-events-none z-1">
|
||||||
|
<div className="absolute top-[15%] left-[10%] text-4xl text-white/15 animate-tech-float">🖥️</div>
|
||||||
|
<div className="absolute top-[25%] right-[15%] text-4xl text-white/15 animate-tech-float" style={{ animationDelay: '2s' }}>⚙️</div>
|
||||||
|
<div className="absolute bottom-[20%] left-[15%] text-4xl text-white/15 animate-tech-float" style={{ animationDelay: '1s' }}>🚀</div>
|
||||||
|
<div className="absolute bottom-[30%] right-[10%] text-4xl text-white/15 animate-tech-float" style={{ animationDelay: '3s' }}>💻</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
47
banquise-website/src/components/sections/ServicesSection.tsx
Normal file
47
banquise-website/src/components/sections/ServicesSection.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
// Define interface directly in the component file
|
||||||
|
interface Service {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
image: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ServicesSectionProps {
|
||||||
|
services: Service[];
|
||||||
|
onServiceClick: (service: Service) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ServicesSection: React.FC<ServicesSectionProps> = ({ services, onServiceClick }) => (
|
||||||
|
<section id="services" className="relative z-2 pt-12 pb-20 mt-0 mb-0 w-full max-w-6xl mx-auto px-8">
|
||||||
|
<div className="w-20 h-1 bg-gradient-to-r from-banquise-blue-lightest to-banquise-blue mx-auto mb-8 rounded-full"></div>
|
||||||
|
<h2 className="text-banquise-gray text-4xl mb-4 text-center font-heading font-bold tracking-tight" style={{ textShadow: '0 2px 4px rgba(0, 0, 0, 0.2)' }}>
|
||||||
|
Nos Services
|
||||||
|
</h2>
|
||||||
|
<p className="text-banquise-gray text-xl opacity-90 mb-14 max-w-4xl text-center mx-auto" style={{ textShadow: '0 1px 3px rgba(0, 0, 0, 0.2)' }}>
|
||||||
|
Cliquez sur un iceberg pour accéder au service correspondant
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="relative w-full max-w-5xl h-auto min-h-96 z-2 flex justify-center items-center mx-auto my-12 p-0 gap-[5%] flex-wrap">
|
||||||
|
{services.map((service, index) => (
|
||||||
|
<div
|
||||||
|
key={service.name}
|
||||||
|
className={`relative cursor-pointer no-underline w-64 h-52 flex items-center justify-center transition-transform duration-300 z-3 m-6 hover:-translate-y-4 ${
|
||||||
|
index === 0 ? 'animate-float-1' : index === 1 ? 'animate-float-2' : 'animate-float-3'
|
||||||
|
}`}
|
||||||
|
onClick={() => onServiceClick(service)}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={service.image}
|
||||||
|
alt={`Iceberg ${service.name}`}
|
||||||
|
className="w-full h-auto max-w-64 max-h-52 object-contain"
|
||||||
|
style={{ filter: 'drop-shadow(0 10px 15px rgba(0, 0, 0, 0.3))' }}
|
||||||
|
/>
|
||||||
|
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-banquise-blue-dark font-bold text-xl bg-white/92 py-3 px-5 rounded-lg text-center shadow-lg z-4 font-heading tracking-tight border border-banquise-blue-lightest/80 backdrop-blur-sm transition-all duration-300 min-w-40 max-w-[90%] w-auto hover:bg-white/97 hover:shadow-xl hover:-translate-y-1 hover:text-banquise-blue" style={{ boxShadow: '0 4px 15px rgba(0, 0, 0, 0.15), 0 0 0 2px rgba(165, 240, 255, 0.5)' }}>
|
||||||
|
{service.name}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
@ -0,0 +1,39 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export const TechFeaturesSection: React.FC = () => (
|
||||||
|
<section className="pt-12 pb-16 relative z-2 w-full max-w-6xl mx-auto px-8">
|
||||||
|
<div className="w-20 h-1 bg-gradient-to-r from-banquise-blue-lightest to-banquise-blue mx-auto mb-8 rounded-full"></div>
|
||||||
|
<h2 className="text-banquise-gray text-4xl mb-4 text-center font-heading font-bold tracking-tight" style={{ textShadow: '0 2px 4px rgba(0, 0, 0, 0.2)' }}>
|
||||||
|
Technologies Avancées
|
||||||
|
</h2>
|
||||||
|
<p className="text-banquise-gray text-xl opacity-90 mb-14 max-w-4xl text-center mx-auto" style={{ textShadow: '0 1px 3px rgba(0, 0, 0, 0.2)' }}>
|
||||||
|
Découvrez les outils et services que nous mettons à votre disposition
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 w-full">
|
||||||
|
<div className="bg-banquise-blue-dark/10 rounded-xl p-8 flex flex-col items-center text-center transition-all duration-300 border border-white/5 hover:-translate-y-2 hover:bg-banquise-blue-dark/20">
|
||||||
|
<div className="text-4xl mb-6 text-banquise-blue-lightest bg-banquise-blue-dark/30 w-18 h-18 flex items-center justify-center rounded-full shadow-lg">
|
||||||
|
📚
|
||||||
|
</div>
|
||||||
|
<h3 className="text-xl mb-4 text-banquise-gray font-heading font-semibold">Documentation</h3>
|
||||||
|
<p className="text-banquise-gray/85 leading-relaxed">Accédez à notre wiki complet avec guides et tutoriels détaillés.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-banquise-blue-dark/10 rounded-xl p-8 flex flex-col items-center text-center transition-all duration-300 border border-white/5 hover:-translate-y-2 hover:bg-banquise-blue-dark/20">
|
||||||
|
<div className="text-4xl mb-6 text-banquise-blue-lightest bg-banquise-blue-dark/30 w-18 h-18 flex items-center justify-center rounded-full shadow-lg">
|
||||||
|
🔧
|
||||||
|
</div>
|
||||||
|
<h3 className="text-xl mb-4 text-banquise-gray font-heading font-semibold">Gestion de Code</h3>
|
||||||
|
<p className="text-banquise-gray/85 leading-relaxed">Gitea pour le versioning et la collaboration sur vos projets.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-banquise-blue-dark/10 rounded-xl p-8 flex flex-col items-center text-center transition-all duration-300 border border-white/5 hover:-translate-y-2 hover:bg-banquise-blue-dark/20">
|
||||||
|
<div className="text-4xl mb-6 text-banquise-blue-lightest bg-banquise-blue-dark/30 w-18 h-18 flex items-center justify-center rounded-full shadow-lg">
|
||||||
|
🎮
|
||||||
|
</div>
|
||||||
|
<h3 className="text-xl mb-4 text-banquise-gray font-heading font-semibold">Panel de Jeux</h3>
|
||||||
|
<p className="text-banquise-gray/85 leading-relaxed">Interface de gestion pour vos serveurs de jeux préférés.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
28
banquise-website/src/components/ui/AccordionItem.tsx
Normal file
28
banquise-website/src/components/ui/AccordionItem.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
// Define interface directly in the component file
|
||||||
|
interface AccordionItemProps {
|
||||||
|
title: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
isOpen: boolean;
|
||||||
|
onToggle: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AccordionItem: React.FC<AccordionItemProps> = ({ title, children, isOpen, onToggle }) => (
|
||||||
|
<div className={`bg-banquise-blue-dark/10 rounded-xl overflow-hidden border border-banquise-blue-lightest/20 transition-all duration-300 shadow-sm ${isOpen ? 'shadow-lg' : ''} hover:bg-banquise-blue-dark/20 hover:shadow-md`}>
|
||||||
|
<div
|
||||||
|
className="p-5 cursor-pointer flex items-center justify-between font-semibold text-banquise-gray bg-banquise-blue-dark/20 transition-all duration-200 text-lg select-none hover:bg-banquise-blue/20"
|
||||||
|
onClick={onToggle}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
<span className={`text-xl transition-transform duration-300 text-banquise-blue-lightest ${isOpen ? 'rotate-180' : ''}`}>
|
||||||
|
▼
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className={`transition-all duration-500 overflow-hidden bg-banquise-blue-dark/5 ${isOpen ? 'max-h-1000 p-6' : 'max-h-0'}`}>
|
||||||
|
<div className="text-banquise-gray/90 leading-relaxed">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
41
banquise-website/src/components/ui/Popup.tsx
Normal file
41
banquise-website/src/components/ui/Popup.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
// Define interface directly in the component file
|
||||||
|
interface Service {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
image: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PopupProps {
|
||||||
|
service: Service;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Popup: React.FC<PopupProps> = ({ service, onClose }) => (
|
||||||
|
<div className="fixed inset-0 bg-black/70 flex justify-center items-center z-50 p-4 backdrop-blur-sm animate-fadeIn">
|
||||||
|
<div className="bg-gradient-to-br from-banquise-gray to-blue-50 text-banquise-blue-dark rounded-xl p-8 max-w-lg w-full shadow-2xl relative overflow-hidden animate-slideUp">
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="absolute top-4 right-4 bg-transparent border-0 text-2xl cursor-pointer text-banquise-blue-dark flex items-center justify-center w-8 h-8 rounded-full transition-colors hover:bg-banquise-blue/10 p-0"
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
<h2 className="font-heading text-3xl mt-0 mb-4 text-banquise-blue-dark leading-tight">
|
||||||
|
{service.name}
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg leading-relaxed mb-6 text-banquise-blue-dark">
|
||||||
|
Accédez directement au service {service.name} en cliquant sur le bouton ci-dessous.
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
href={service.url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="inline-flex items-center bg-banquise-blue text-white border-0 py-3 px-6 rounded-md cursor-pointer no-underline font-semibold tracking-wide shadow-lg transition-all duration-200 hover:bg-banquise-blue/80 hover:-translate-y-0.5 hover:shadow-xl focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-banquise-blue-light"
|
||||||
|
>
|
||||||
|
<span className="mr-2 text-lg">🚀</span>
|
||||||
|
Accéder à {service.name}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
@ -2,102 +2,8 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
/* Système typographique moderne */
|
/* Variables CSS pour les polices */
|
||||||
:root {
|
:root {
|
||||||
--font-heading: 'Space Grotesk', sans-serif;
|
--font-heading: 'Dela Gothic One', sans-serif;
|
||||||
--font-body: 'Inter', system-ui, sans-serif;
|
--font-body: 'Roboto', sans-serif;
|
||||||
|
|
||||||
font-family: var(--font-body);
|
|
||||||
line-height: 1.5;
|
|
||||||
font-weight: 400;
|
|
||||||
|
|
||||||
color-scheme: light dark;
|
|
||||||
color: rgba(255, 255, 255, 0.87);
|
|
||||||
background-color: #242424;
|
|
||||||
|
|
||||||
font-synthesis: none;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hiérarchie typographique */
|
|
||||||
h1, h2, h3, h4, h5, h6, .site-name, .welcome-title {
|
|
||||||
font-family: var(--font-heading);
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.2;
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 3.2em;
|
|
||||||
line-height: 1.1;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 2.4em;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 1.8em;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
p, span, div, a, button, input {
|
|
||||||
font-family: var(--font-body);
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #646cff;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #535bf2;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
min-width: 320px;
|
|
||||||
min-height: 100vh;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding: 0.6em 1.2em;
|
|
||||||
font-size: 1em;
|
|
||||||
font-weight: 500;
|
|
||||||
font-family: var(--font-body);
|
|
||||||
background-color: #1a1a1a;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: border-color 0.25s;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
border-color: #646cff;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:focus,
|
|
||||||
button:focus-visible {
|
|
||||||
outline: 4px auto -webkit-focus-ring-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: light) {
|
|
||||||
:root {
|
|
||||||
color: #213547;
|
|
||||||
background-color: #ffffff;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: #747bff;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,109 @@ export default {
|
|||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
// Vous pouvez personnaliser vos couleurs ici
|
banquise: {
|
||||||
|
blue: '#40B4FF',
|
||||||
|
'blue-dark': '#1F5D89',
|
||||||
|
'blue-light': '#69B7E2',
|
||||||
|
'blue-lightest': '#A5F0FF',
|
||||||
|
gray: '#F6F6F6',
|
||||||
|
}
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
// Personnalisation des polices
|
heading: ['Dela Gothic One', 'sans-serif'],
|
||||||
}
|
body: ['Roboto', 'sans-serif'],
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
'float': 'float 6s ease-in-out infinite',
|
||||||
|
'float-1': 'float1 5s ease-in-out infinite',
|
||||||
|
'float-2': 'float2 6s ease-in-out infinite',
|
||||||
|
'float-3': 'float3 7s ease-in-out infinite',
|
||||||
|
'wave': 'wave 10s linear infinite',
|
||||||
|
'wave-reverse': 'waveReverse 15s linear infinite',
|
||||||
|
'wave-1': 'wave 20s linear infinite',
|
||||||
|
'wave-2': 'waveReverse 15s linear infinite',
|
||||||
|
'wave-3': 'wave 12s linear infinite',
|
||||||
|
'rise': 'rise 10s infinite ease-in',
|
||||||
|
'tech-float': 'tech-float 10s ease-in-out infinite',
|
||||||
|
'gentle-float': 'gentle-float 6s ease-in-out infinite',
|
||||||
|
'fadeIn': 'fadeIn 0.2s ease-out',
|
||||||
|
'slideUp': 'slideUp 0.3s ease-out',
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
float: {
|
||||||
|
'0%, 100%': { transform: 'translateY(0)' },
|
||||||
|
'50%': { transform: 'translateY(-10px)' },
|
||||||
|
},
|
||||||
|
float1: {
|
||||||
|
'0%, 100%': { transform: 'translateY(0)' },
|
||||||
|
'50%': { transform: 'translateY(-15px)' },
|
||||||
|
},
|
||||||
|
float2: {
|
||||||
|
'0%, 100%': { transform: 'translateY(0)' },
|
||||||
|
'50%': { transform: 'translateY(-20px)' },
|
||||||
|
},
|
||||||
|
float3: {
|
||||||
|
'0%, 100%': { transform: 'translateY(0)' },
|
||||||
|
'50%': { transform: 'translateY(-10px)' },
|
||||||
|
},
|
||||||
|
'tech-float': {
|
||||||
|
'0%, 100%': { transform: 'translateY(0) rotate(0deg)', opacity: '0.15' },
|
||||||
|
'50%': { transform: 'translateY(-20px) rotate(10deg)', opacity: '0.25' },
|
||||||
|
},
|
||||||
|
'gentle-float': {
|
||||||
|
'0%, 100%': { transform: 'translateY(0)' },
|
||||||
|
'50%': { transform: 'translateY(-10px)' },
|
||||||
|
},
|
||||||
|
wave: {
|
||||||
|
'0%': { backgroundPosition: '0' },
|
||||||
|
'100%': { backgroundPosition: '1200px' },
|
||||||
|
},
|
||||||
|
waveReverse: {
|
||||||
|
'0%': { backgroundPosition: '1200px' },
|
||||||
|
'100%': { backgroundPosition: '0' },
|
||||||
|
},
|
||||||
|
rise: {
|
||||||
|
'0%': {
|
||||||
|
bottom: '-100px',
|
||||||
|
transform: 'translateX(0)',
|
||||||
|
opacity: '0.8',
|
||||||
|
},
|
||||||
|
'50%': {
|
||||||
|
transform: 'translateX(40px)',
|
||||||
|
opacity: '0.4',
|
||||||
|
},
|
||||||
|
'100%': {
|
||||||
|
bottom: '1080px',
|
||||||
|
transform: 'translateX(-40px)',
|
||||||
|
opacity: '0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fadeIn: {
|
||||||
|
from: { opacity: '0' },
|
||||||
|
to: { opacity: '1' },
|
||||||
|
},
|
||||||
|
slideUp: {
|
||||||
|
from: { transform: 'translateY(30px)', opacity: '0' },
|
||||||
|
to: { transform: 'translateY(0)', opacity: '1' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
backdropBlur: {
|
||||||
|
'xs': '2px',
|
||||||
|
},
|
||||||
|
backgroundImage: {
|
||||||
|
'wave-pattern': "url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1200 120\" preserveAspectRatio=\"none\"><path d=\"M0,0V46.29c47.79,22.2,103.59,32.17,158,28,70.36-5.37,136.33-33.31,206.8-37.5C438.64,32.43,512.34,53.67,583,72.05c69.27,18,138.3,24.88,209.4,13.08,36.15-6,69.85-17.84,104.45-29.34C989.49,25,1113-14.29,1200,52.47V0Z\" opacity=\".25\" fill=\"%231F5D89\"/><path d=\"M0,0V15.81C13,36.92,27.64,56.86,47.69,72.05,99.41,111.27,165,111,224.58,91.58c31.15-10.15,60.09-26.07,89.67-39.8,40.92-19,84.73-46,130.83-49.67,36.26-2.85,70.9,9.42,98.6,31.56,31.77,25.39,62.32,62,103.63,73,40.44,10.79,81.35-6.69,119.13-24.28s75.16-39,116.92-43.05c59.73-5.85,113.28,22.88,168.9,38.84,30.2,8.66,59,6.17,87.09-7.5,22.43-10.89,48-26.93,60.65-49.24V0Z\" opacity=\".5\" fill=\"%231F5D89\"/><path d=\"M0,0V5.63C149.93,59,314.09,71.32,475.83,42.57c43-7.64,84.23-20.12,127.61-26.46,59-8.63,112.48,12.24,165.56,35.4C827.93,77.22,886,95.24,951.2,90c86.53-7,172.46-45.71,248.8-84.81V0Z\" fill=\"%231F5D89\"/></svg>')",
|
||||||
|
'ocean-gradient': 'linear-gradient(180deg, #40B4FF 0%, #69B7E2 50%, #1F5D89 100%)',
|
||||||
|
},
|
||||||
|
maxHeight: {
|
||||||
|
'0': '0',
|
||||||
|
'1000': '1000px',
|
||||||
|
},
|
||||||
|
spacing: {
|
||||||
|
'72': '18rem',
|
||||||
|
'80': '20rem',
|
||||||
|
'88': '22rem',
|
||||||
|
'96': '24rem',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user