(null);
-
- // FAQ items for the about section
- const faqItems = useMemo(() => [
- {
- question: "Qui sommes-nous ?",
- answer: (
- <>
- 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.
- 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.
- >
- )
- },
- {
- question: "Comment candidater pour rejoindre La Banquise ?",
- answer: (
- <>
- Pour nous rejoindre, rien de plus simple :
-
-
- Rejoignez notre serveur Discord
- Donnez votre login EPITA dans un ticket, ou expliquer votre situation/besoins.
- Un moderateur vous mettra le role necessaire pour acceder au salons avec tout nos projets sur discord !
-
-
- 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 !
-
- Rejoindre notre Discord
-
- >
- )
- },
- {
- question: "Quels sont nos objectifs ?",
- answer: (
- <>
- Nos principaux objectifs sont :
-
- Former les étudiants aux technologies d'hébergement et de réseau
- Fournir des services informatiques de qualité aux étudiants et associations de l'EPITA
- Promouvoir le partage de connaissances et l'entraide
- Créer un environnement d'apprentissage pratique par l'expérience
- Maintenir une infrastructure robuste et sécurisée
-
- >
- )
- },
- {
- question: "Comment utiliser nos services ?",
- answer: (
- <>
- Pour accéder à nos services :
-
- Connectez-vous au service souhaité avec vos identifiants, pour le moment crees par un admin
- Consultez notre Wiki pour obtenir de l'aide sur l'utilisation de chaque service !
-
- Si vous rencontrez des difficultés, n'hésitez pas à demander de l'aide sur notre Discord.
-
- Se Connecter
-
- >
- )
- },
- {
- question: "Comment contribuer a un projet ?",
- answer: (
- <>
- Il existe plusieurs façons de contribuer aux projets La Banquise :
-
- Deployer des services
- Experimenter et documenter le fonctionnement de technologies (k8s, openstack...)
- Aider a gerer les ressources de l'asso
- Contribuer au code source de nos projets via Gitea
- Rédiger ou améliorer la documentation sur notre Wiki
- Proposer de nouvelles idées de services ou d'améliorations
- Aider d'autres utilisateurs sur notre Discord
-
- Toutes les contributions sont les bienvenues, même les plus modestes !
- >
- )
- },
- ], []);
-
- const toggleAccordion = (index: number) => {
- setActiveAccordion(activeAccordion === index ? null : index);
- };
-
- return (
-
-
Passer au contenu principal
-
-
-
-
-
- {renderBubbles}
-
-
-
-
-
-
-
- Association La Banquise
-
- Association d'hébergement et lab réseau pour tous les étudiants et associations de l'EPITA !
-
-
-
-
-
-
- Notre infrastructure
-
- 25+ serveurs pour répondre à vos besoins
-
-
- Un local a EPITA Lyon, prochainement a Paris ?
-
-
-
-
-
-
-
Serveurs performants
-
- Infrastructure optimisée pour assurer des performances élevées et une disponibilité maximale de vos applications
-
-
-
-
-
-
-
-
Stockage sécurisé
-
- Solutions de stockage distribuées avec redondance pour garantir l'intégrité et la durabilité de vos données
-
-
-
-
-
-
-
-
Réseau optimisé
-
- Architecture réseau à haute disponibilité avec une faible latence pour vos applications critiques
-
-
-
-
-
-
-
-
Sécurité renforcée
-
- Protection contre les menaces avec systèmes de sécurité modernes et mises à jour régulières
-
-
-
-
-
-
-
- Nos services
-
- Explorez notre écosystème de services conçus pour répondre à vos besoins.
-
-
-
-
-
-
-
- À propos de nous
-
- Découvrez notre mission et posez-nous vos questions
-
-
-
-
-
-
-
-
- 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.
-
-
-
- {faqItems.map((item, index) => (
-
-
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}
-
-
-
- {item.answer}
-
-
- ))}
-
-
-
-
- {selectedService !== null && (
-
- )}
-
-
-
-
-
-
-
- );
+// Define Service interface directly in App
+interface Service {
+ name: string;
+ url: string;
+ image: string;
+ description: string;
+ features: string[];
+ icon: string;
}
+const App: React.FC = () => {
+ // Define services directly in the component with enhanced data
+ const services: Service[] = [
+ {
+ name: "Wiki",
+ url: URLS.services.wiki,
+ image: "/src/assets/iceberg.png",
+ icon: "📚",
+ description: "Notre wiki collaboratif est votre centre de documentation technique. Accédez à des guides détaillés, des tutoriels et de la documentation API pour tous nos services.",
+ features: [
+ "Documentation collaborative en temps réel",
+ "Guides d'installation détaillés",
+ "API et références techniques",
+ "Tutoriels pas à pas",
+ "Base de connaissances communautaire",
+ "Recherche avancée intégrée"
+ ]
+ },
+ {
+ name: "Gitea",
+ url: URLS.services.gitea,
+ image: "/src/assets/iceberg.png",
+ icon: "🔧",
+ description: "Instance Gitea auto-hébergée pour la gestion de vos dépôts Git. Collaborez sur vos projets avec un contrôle total sur votre code source.",
+ features: [
+ "Dépôts Git illimités",
+ "Issues et pull requests",
+ "Actions CI/CD intégrées",
+ "Gestion d'équipes et permissions",
+ "Interface web intuitive",
+ "Intégration avec outils externes"
+ ]
+ },
+ {
+ name: "Panel",
+ url: URLS.services.panel,
+ image: "/src/assets/iceberg.png",
+ icon: "🎮",
+ description: "Interface de gestion centralisée pour vos serveurs de jeux. Déployez, configurez et surveillez vos serveurs gaming en quelques clics.",
+ features: [
+ "Déploiement automatisé de serveurs",
+ "Monitoring en temps réel",
+ "Gestion des ressources système",
+ "Interface d'administration web",
+ "Support multi-jeux",
+ "Sauvegarde automatique des données"
+ ]
+ }
+ ];
+
+ const [selectedService, setSelectedService] = useState(null);
+
+ // Inline accordion logic
+ const [openAccordion, setOpenAccordion] = useState(null);
+ const toggleAccordion = (title: string) => {
+ setOpenAccordion(openAccordion === title ? null : title);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+ {/* Bouton de retour en haut */}
+
+
+ {selectedService && (
+
setSelectedService(null)} />
+ )}
+
+ );
+};
+
export default App;
diff --git a/banquise-website/src/components/layout/Footer.tsx b/banquise-website/src/components/layout/Footer.tsx
new file mode 100644
index 0000000..0072ea6
--- /dev/null
+++ b/banquise-website/src/components/layout/Footer.tsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import { URLS, SITE_CONFIG } from '../../config/constants';
+
+export const Footer: React.FC = () => (
+
+);
diff --git a/banquise-website/src/components/layout/MobileMenu.tsx b/banquise-website/src/components/layout/MobileMenu.tsx
new file mode 100644
index 0000000..a233ef8
--- /dev/null
+++ b/banquise-website/src/components/layout/MobileMenu.tsx
@@ -0,0 +1,154 @@
+import React, { useEffect } from 'react';
+import banquiseServer from '../../assets/banquise_server.svg'
+import { URLS, SITE_CONFIG } from '../../config/constants';
+import { commonStyles } from '../../styles/components';
+
+interface MobileMenuProps {
+ isOpen: boolean;
+ onClose: () => void;
+}
+
+export const MobileMenu: React.FC = ({ isOpen, onClose }) => {
+ useEffect(() => {
+ if (isOpen) {
+ document.body.style.overflow = 'hidden';
+ } else {
+ document.body.style.overflow = 'unset';
+ }
+
+ return () => {
+ document.body.style.overflow = 'unset';
+ };
+ }, [isOpen]);
+
+ return (
+
+ {/* Overlay */}
+
+
+ {/* Menu mobile */}
+
+
+ {/* Header */}
+
+
+
+
+
+
+
+
+ {SITE_CONFIG.name}
+
+
Menu Navigation
+
+
+
+
+
+
+
+
+
+
+ {/* Navigation */}
+
+
+ {/* Navigation Links */}
+
+
+ {/* CTA Button */}
+
+
+
+ {/* Footer */}
+
+
+
+ © 2024 {SITE_CONFIG.name}
+
+
+
+
+ {/* Effet glassmorphism */}
+
+
+
+ );
+};
diff --git a/banquise-website/src/components/layout/Navigation.tsx b/banquise-website/src/components/layout/Navigation.tsx
new file mode 100644
index 0000000..70935b2
--- /dev/null
+++ b/banquise-website/src/components/layout/Navigation.tsx
@@ -0,0 +1,147 @@
+import React, { useState, useEffect } from 'react';
+import { MobileMenu } from './MobileMenu';
+import banquiseServer from '/src/assets/banquise_server.svg'
+import { URLS, SITE_CONFIG } from '../../config/constants';
+import { commonStyles } from '../../styles/components';
+
+export const Navigation: React.FC = () => {
+ const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
+ const [scrolled, setScrolled] = useState(false);
+
+ useEffect(() => {
+ const handleScroll = () => {
+ const isScrolled = window.scrollY > 20;
+ setScrolled(isScrolled);
+ };
+
+ window.addEventListener('scroll', handleScroll);
+ return () => window.removeEventListener('scroll', handleScroll);
+ }, []);
+
+ useEffect(() => {
+ const handleResize = () => {
+ if (window.innerWidth >= 768) {
+ setMobileMenuOpen(false);
+ }
+ };
+
+ window.addEventListener('resize', handleResize);
+ return () => window.removeEventListener('resize', handleResize);
+ }, []);
+
+ return (
+ <>
+
+
+
+
+ {/* Logo section */}
+
+
+
+
+
+
+
+ {SITE_CONFIG.name}
+
+
+ {SITE_CONFIG.tagline}
+
+
+
+
+ {/* Navigation links desktop */}
+
+
+ {/* Action buttons desktop */}
+
+
+ {/* Mobile menu button */}
+
setMobileMenuOpen(!mobileMenuOpen)}
+ aria-label={mobileMenuOpen ? "Fermer le menu" : "Ouvrir le menu"}
+ aria-expanded={mobileMenuOpen}
+ >
+
+
+
+
+
+
+
+
+
+ {/* Glassmorphism effect bar */}
+
+
+
+ {/* Spacer pour compenser la navbar fixed */}
+
+
+ {/* Menu mobile */}
+ setMobileMenuOpen(false)}
+ />
+ >
+ );
+};
diff --git a/banquise-website/src/components/sections/AboutSection.tsx b/banquise-website/src/components/sections/AboutSection.tsx
new file mode 100644
index 0000000..e71693f
--- /dev/null
+++ b/banquise-website/src/components/sections/AboutSection.tsx
@@ -0,0 +1,124 @@
+import React from 'react';
+import { AccordionItem } from '../ui/AccordionItem';
+import { URLS } from '../../config/constants';
+import { commonStyles } from '../../styles/components';
+
+interface AboutSectionProps {
+ openAccordion: string | null;
+ toggleAccordion: (title: string) => void;
+}
+
+export const AboutSection: React.FC = ({ openAccordion, toggleAccordion }) => (
+
+
+ {/* Header */}
+
+
+
+ À Propos de La Banquise
+
+
+ Une communauté passionnée qui propose des services d'hébergement et des outils collaboratifs pour les développeurs et les gamers.
+
+
+
+ {/* FAQ Section */}
+
+
+ ❓
+ Questions Fréquentes
+
+
+
toggleAccordion("mission")}
+ >
+
+
+ Former les étudiants au déploiment et a la gestion d'une infra, et de maitriser des technologies entreprise grade.
+ Cela permet de fournir une plateforme stable et accessible pour héberger vos projets, partager vos connaissances et jouer ensemble !
+
+
+ Nous croyons en la puissance de la collaboration et mettons à disposition des outils modernes pour faciliter le travail en équipe.
+
+
+ Collaboration
+ Innovation
+ Accessibilité
+
+
+
+
+
toggleAccordion("services")}
+ >
+
+
+
+
📚
+
+
Wiki
+
Documentation collaborative et guides détaillés
+
+
+
+
+
🔧
+
+
Gitea
+
Gestion de versions Git auto-hébergée
+
+
+
+
+
🎮
+
+
Panel de Jeux
+
Interface de gestion pour serveurs de jeux
+
+
+
+
+ Tous nos services sont maintenus avec soin et régulièrement mis à jour pour garantir une expérience optimale.
+
+
+
+
+
toggleAccordion("community")}
+ >
+
+
+ Rejoignez notre serveur Discord pour rejoindre l'asso, échanger avec nous, obtenir de l'aide et rester informé des dernières nouveautés !
+
+
+
+
+ 💬
+ Comment rejoindre l'asso ?
+
+
+ • Creez un ticket banquise
+ • Donnez votre login EPITA ou expliquez votre situation
+ • Un moderateur validera votre demande et vous donnera acces aux salons discord de l'asso !
+
+
+
+ 🚀
+ Rejoindre Discord
+
+
+
+
+
+
+
+);
diff --git a/banquise-website/src/components/sections/HeroSection.tsx b/banquise-website/src/components/sections/HeroSection.tsx
new file mode 100644
index 0000000..b6b8eac
--- /dev/null
+++ b/banquise-website/src/components/sections/HeroSection.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import banquiseServer from '/src/assets/banquise_server.svg'
+
+export const HeroSection: React.FC = () => (
+
+
+
+
+
+
+ Bienvenue sur La Banquise
+
+
+
+ Association d'hébergement et lab réseau pour tous les étudiants et associations de l'EPITA !
+
+
+
+ Découvrir nos services
+ →
+
+
+);
diff --git a/banquise-website/src/components/sections/ServicesSection.tsx b/banquise-website/src/components/sections/ServicesSection.tsx
new file mode 100644
index 0000000..ad58cef
--- /dev/null
+++ b/banquise-website/src/components/sections/ServicesSection.tsx
@@ -0,0 +1,63 @@
+import React from 'react';
+
+// Declare the Service interface here
+interface Service {
+ name: string;
+ url: string;
+ image: string;
+ icon: string;
+ description: string;
+ features: string[];
+}
+
+// Define interface directly in the component file
+interface ServicesSectionProps {
+ services: Service[];
+ onServiceClick: (service: Service) => void;
+}
+
+export const ServicesSection: React.FC = ({ services, onServiceClick }) => (
+
+
+
+ Nos Services
+
+
+ Cliquez sur un service pour découvrir toutes ses fonctionnalités
+
+
+
+ {services.map((service) => (
+
onServiceClick(service)}
+ >
+ {/* Icon */}
+
+ {service.icon}
+
+
+ {/* Service name */}
+
+ {service.name}
+
+
+ {/* Short teaser description */}
+
+ {service.description.split('.')[0]}.
+
+
+ {/* CTA */}
+
+ Découvrir toutes les fonctionnalités
+ →
+
+
+ {/* Subtle hover effect */}
+
+
+ ))}
+
+
+);
diff --git a/banquise-website/src/components/sections/TechFeaturesSection.tsx b/banquise-website/src/components/sections/TechFeaturesSection.tsx
new file mode 100644
index 0000000..417c98f
--- /dev/null
+++ b/banquise-website/src/components/sections/TechFeaturesSection.tsx
@@ -0,0 +1,47 @@
+import React from 'react';
+
+export const TechFeaturesSection: React.FC = () => (
+
+
+
+ Notre Infrastructure
+
+
+ 25+ serveurs pour répondre à vos besoins
+
+
+
+
+
+ 🚀
+
+
Serveurs performants
+
Infrastructure optimisée pour assurer des performances élevées et une disponibilité maximale de vos applications
+
+
+
+
+ 💾
+
+
Stockage sécurisé
+
Solutions de stockage distribuées avec redondance pour garantir l'intégrité et la durabilité de vos données
+
+
+
+
+ 🌐
+
+
Réseau optimisé
+
Architecture réseau à haute disponibilité avec une faible latence pour vos applications critiques
+
+
+
+
+ 🛡️
+
+
Sécurité renforcée
+
Protection contre les menaces avec systèmes de sécurité modernes et mises à jour régulières
+
+
+
+);
diff --git a/banquise-website/src/components/ui/AccordionItem.tsx b/banquise-website/src/components/ui/AccordionItem.tsx
new file mode 100644
index 0000000..2f7fd4d
--- /dev/null
+++ b/banquise-website/src/components/ui/AccordionItem.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+
+// Définir l'interface localement :
+interface AccordionItemProps {
+ title: string;
+ children: React.ReactNode;
+ isOpen: boolean;
+ onToggle: () => void;
+}
+
+export const AccordionItem: React.FC = ({ title, children, isOpen, onToggle }) => (
+
+
+ {title}
+
+ ▼
+
+
+
+
+);
diff --git a/banquise-website/src/components/ui/ParallaxBackground.tsx b/banquise-website/src/components/ui/ParallaxBackground.tsx
new file mode 100644
index 0000000..b8e33b5
--- /dev/null
+++ b/banquise-website/src/components/ui/ParallaxBackground.tsx
@@ -0,0 +1,146 @@
+import React, { useEffect, useState } from 'react';
+
+export const ParallaxBackground: React.FC = () => {
+ const [scrollY, setScrollY] = useState(0);
+
+ useEffect(() => {
+ const handleScroll = () => {
+ setScrollY(window.scrollY);
+ };
+
+ window.addEventListener('scroll', handleScroll);
+ return () => window.removeEventListener('scroll', handleScroll);
+ }, []);
+
+ // Éléments flottants avec différentes vitesses de parallaxe
+ const floatingElements = [
+ // Serveurs et équipements
+ { icon: '🖥️', x: 10, y: 20, speed: 0.3, size: 'text-2xl', opacity: 0.1 },
+ { icon: '🖲️', x: 85, y: 15, speed: 0.2, size: 'text-xl', opacity: 0.08 },
+ { icon: '⚙️', x: 75, y: 45, speed: 0.4, size: 'text-3xl', opacity: 0.12 },
+ { icon: '🔧', x: 15, y: 60, speed: 0.25, size: 'text-lg', opacity: 0.06 },
+ { icon: '💾', x: 90, y: 70, speed: 0.35, size: 'text-2xl', opacity: 0.1 },
+
+ // Code et développement
+ { icon: '<>', x: 30, y: 35, speed: 0.15, size: 'text-xl', opacity: 0.08, isText: true },
+ { icon: '{ }', x: 60, y: 25, speed: 0.28, size: 'text-2xl', opacity: 0.1, isText: true },
+ { icon: '#!/bin', x: 5, y: 80, speed: 0.2, size: 'text-sm', opacity: 0.06, isText: true },
+ { icon: 'git', x: 80, y: 85, speed: 0.32, size: 'text-lg', opacity: 0.08, isText: true },
+
+ // Réseau et connectivité
+ { icon: '🌐', x: 45, y: 10, speed: 0.22, size: 'text-2xl', opacity: 0.09 },
+ { icon: '🔗', x: 25, y: 75, speed: 0.18, size: 'text-xl', opacity: 0.07 },
+ { icon: '📡', x: 70, y: 55, speed: 0.26, size: 'text-lg', opacity: 0.08 },
+
+ // Sécurité
+ { icon: '🔒', x: 55, y: 40, speed: 0.3, size: 'text-xl', opacity: 0.09 },
+ { icon: '🛡️', x: 35, y: 65, speed: 0.24, size: 'text-2xl', opacity: 0.1 },
+ { icon: '🔑', x: 85, y: 30, speed: 0.16, size: 'text-lg', opacity: 0.07 },
+
+ // Données et stockage
+ { icon: '💿', x: 20, y: 45, speed: 0.28, size: 'text-xl', opacity: 0.08 },
+ { icon: '📊', x: 65, y: 75, speed: 0.22, size: 'text-2xl', opacity: 0.09 },
+ { icon: '📈', x: 40, y: 20, speed: 0.34, size: 'text-lg', opacity: 0.07 },
+
+ // Éléments techniques supplémentaires
+ { icon: 'sudo', x: 12, y: 90, speed: 0.19, size: 'text-sm', opacity: 0.06, isText: true },
+ { icon: 'SSH', x: 78, y: 12, speed: 0.31, size: 'text-base', opacity: 0.08, isText: true },
+ { icon: 'API', x: 92, y: 50, speed: 0.27, size: 'text-lg', opacity: 0.09, isText: true },
+ { icon: 'TCP', x: 8, y: 30, speed: 0.23, size: 'text-base', opacity: 0.07, isText: true },
+ { icon: 'HTTP', x: 50, y: 80, speed: 0.29, size: 'text-sm', opacity: 0.06, isText: true },
+ ];
+
+ return (
+
+ {/* Grille de fond subtile */}
+
+
+ {/* Particules de code flottantes */}
+
+ {floatingElements.map((element, index) => (
+
+ {element.icon}
+
+ ))}
+
+
+ {/* Lignes de connexion animées */}
+
+
+
+
+
+
+
+
+
+ {/* Lignes de connexion entre les éléments */}
+ {[...Array(8)].map((_, i) => (
+
+ ))}
+
+
+ {/* Cercles de données en mouvement */}
+
+ {[...Array(6)].map((_, i) => (
+
+ ))}
+
+
+ );
+};
diff --git a/banquise-website/src/components/ui/Popup.tsx b/banquise-website/src/components/ui/Popup.tsx
new file mode 100644
index 0000000..8ed8158
--- /dev/null
+++ b/banquise-website/src/components/ui/Popup.tsx
@@ -0,0 +1,141 @@
+import React, { useEffect } from 'react';
+import { URLS } from '../../config/constants';
+
+interface Service {
+ name: string;
+ url: string;
+ image: string;
+ icon: string;
+ description: string;
+ features: string[];
+}
+
+interface PopupProps {
+ service: Service;
+ onClose: () => void;
+}
+
+export const Popup: React.FC = ({ service, onClose }) => {
+ // Empêcher le scroll du body quand la popup est ouverte
+ useEffect(() => {
+ document.body.style.overflow = 'hidden';
+
+ return () => {
+ document.body.style.overflow = 'unset';
+ };
+ }, []);
+
+ return (
+
+
+
+ {/* Bouton de fermeture fixe au-dessus du contenu */}
+
+
+ ×
+
+
+
+ {/* Contenu avec scroll vertical uniquement */}
+
+ {/* Header */}
+
+
+
+ {service.icon}
+
+
+
+ {service.name}
+
+
+ Service d'hébergement professionnel
+
+
+ Haute disponibilité
+ Open Source
+ Communautaire
+
+
+
+
+
+ {/* Content - Forcer le fond blanc */}
+
+ {/* Description */}
+
+ 📋
+ Description détaillée
+
+
+
+ {service.description}
+
+
+
+
+ ✓
+
+
+
99.9% Uptime
+
Disponibilité garantie
+
+
+
+
+ 🔒
+
+
+
Sécurisé
+
SSL & Backups
+
+
+
+
+
+ {/* Fonctionnalités */}
+
+ ⚡
+ Fonctionnalités principales
+
+
+ {service.features.map((feature, index) => (
+
+ ))}
+
+
+ {/* Call to action */}
+
+
+
+
+ {/* Decorative elements */}
+
+
+
+
+ );
+};
diff --git a/banquise-website/src/components/ui/ScrollToTopButton.tsx b/banquise-website/src/components/ui/ScrollToTopButton.tsx
new file mode 100644
index 0000000..a05463b
--- /dev/null
+++ b/banquise-website/src/components/ui/ScrollToTopButton.tsx
@@ -0,0 +1,51 @@
+import React, { useState, useEffect } from 'react';
+
+export const ScrollToTopButton: React.FC = () => {
+ const [isVisible, setIsVisible] = useState(false);
+
+ useEffect(() => {
+ const toggleVisibility = () => {
+ // Afficher le bouton après avoir scrollé 300px
+ setIsVisible(window.scrollY > 300);
+ };
+
+ window.addEventListener('scroll', toggleVisibility);
+ return () => window.removeEventListener('scroll', toggleVisibility);
+ }, []);
+
+ const scrollToTop = () => {
+ window.scrollTo({
+ top: 0,
+ behavior: 'smooth'
+ });
+ };
+
+ return (
+
+
+
+
+
+ {/* Effet de lueur au hover */}
+
+
+ );
+};
diff --git a/banquise-website/src/config/constants.ts b/banquise-website/src/config/constants.ts
new file mode 100644
index 0000000..5a493bf
--- /dev/null
+++ b/banquise-website/src/config/constants.ts
@@ -0,0 +1,20 @@
+export const URLS = {
+ services: {
+ wiki: "https://wiki.la-banquise.fr",
+ gitea: "https://git.la-banquise.fr",
+ panel: "https://panel.la-banquise.fr",
+ auth: "https://auth.la-banquise.fr"
+ },
+ social: {
+ discord: "https://discord.gg/labanquise"
+ },
+ contact: {
+ email: "mailto:contact@la-banquise.fr"
+ }
+} as const;
+
+export const SITE_CONFIG = {
+ name: "La Banquise",
+ description: "Association d'hébergement et lab réseau pour tous les étudiants et associations de l'EPITA",
+ tagline: "Communauté • Hébergement"
+} as const;
diff --git a/banquise-website/src/index.css b/banquise-website/src/index.css
index 29d7987..ca06f66 100644
--- a/banquise-website/src/index.css
+++ b/banquise-website/src/index.css
@@ -2,102 +2,184 @@
@tailwind components;
@tailwind utilities;
-/* Système typographique moderne */
+/* Variables CSS pour les polices */
:root {
- --font-heading: 'Space Grotesk', sans-serif;
- --font-body: 'Inter', system-ui, 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;
+ --font-heading: 'Dela Gothic One', sans-serif;
+ --font-body: 'Roboto', sans-serif;
}
-/* 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;
+/* Parallax animations */
+@keyframes parallax-slow {
+ 0% { transform: translateY(0px); }
+ 100% { transform: translateY(-50px); }
}
-h1 {
- font-size: 3.2em;
- line-height: 1.1;
- font-weight: 700;
+@keyframes parallax-medium {
+ 0% { transform: translateY(0px); }
+ 100% { transform: translateY(-80px); }
}
-h2 {
- font-size: 2.4em;
- font-weight: 600;
+@keyframes parallax-fast {
+ 0% { transform: translateY(0px); }
+ 100% { transform: translateY(-120px); }
}
-h3 {
- font-size: 1.8em;
- font-weight: 600;
+@keyframes parallax-very-slow {
+ 0% { transform: translateY(0px); }
+ 100% { transform: translateY(-20px); }
}
-p, span, div, a, button, input {
- font-family: var(--font-body);
+/* Floating animations with different speeds */
+@keyframes float-slow {
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
+ 50% { transform: translateY(-20px) rotate(5deg); }
}
-a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
+@keyframes float-medium {
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
+ 50% { transform: translateY(-15px) rotate(-3deg); }
}
-a:hover {
- color: #535bf2;
+@keyframes float-fast {
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
+ 50% { transform: translateY(-10px) rotate(3deg); }
}
+@keyframes float-very-slow {
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
+ 50% { transform: translateY(-30px) rotate(-2deg); }
+}
+
+/* Animations pour les éléments flottants */
+@keyframes float-0 {
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
+ 50% { transform: translateY(-10px) rotate(2deg); }
+}
+
+@keyframes float-1 {
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
+ 33% { transform: translateY(-8px) rotate(-1deg); }
+ 66% { transform: translateY(-15px) rotate(1deg); }
+}
+
+@keyframes float-2 {
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
+ 25% { transform: translateY(-12px) rotate(1deg); }
+ 75% { transform: translateY(-6px) rotate(-2deg); }
+}
+
+/* Animation pour l'élément principal du hero */
+@keyframes gentle-float {
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
+ 50% { transform: translateY(-15px) rotate(1deg); }
+}
+
+.animate-gentle-float {
+ animation: gentle-float 6s ease-in-out infinite;
+}
+
+/* Effet de lueur pour les éléments techniques */
+@keyframes glow-pulse {
+ 0%, 100% {
+ text-shadow: 0 0 5px rgba(168, 218, 255, 0.3),
+ 0 0 10px rgba(168, 218, 255, 0.2),
+ 0 0 15px rgba(168, 218, 255, 0.1);
+ }
+ 50% {
+ text-shadow: 0 0 10px rgba(168, 218, 255, 0.4),
+ 0 0 20px rgba(168, 218, 255, 0.3),
+ 0 0 30px rgba(168, 218, 255, 0.2);
+ }
+}
+
+/* Animation des lignes de connexion */
+@keyframes data-flow {
+ 0% { stroke-dasharray: 0, 100; }
+ 50% { stroke-dasharray: 50, 100; }
+ 100% { stroke-dasharray: 100, 100; }
+}
+
+/* Responsive pour les animations */
+@media (prefers-reduced-motion: reduce) {
+ .animate-gentle-float,
+ .animate-ping,
+ .animate-pulse {
+ animation: none;
+ }
+}
+
+/* Apply animations */
+.animate-parallax-slow {
+ animation: parallax-slow 20s ease-in-out infinite;
+}
+
+.animate-parallax-medium {
+ animation: parallax-medium 15s ease-in-out infinite;
+}
+
+.animate-parallax-fast {
+ animation: parallax-fast 10s ease-in-out infinite;
+}
+
+.animate-parallax-very-slow {
+ animation: parallax-very-slow 30s ease-in-out infinite;
+}
+
+.animate-float-slow {
+ animation: float-slow 8s ease-in-out infinite;
+}
+
+.animate-float-medium {
+ animation: float-medium 6s ease-in-out infinite;
+}
+
+.animate-float-fast {
+ animation: float-fast 4s ease-in-out infinite;
+}
+
+.animate-float-very-slow {
+ animation: float-very-slow 12s ease-in-out infinite;
+}
+
+/* Amélioration du scroll */
+html {
+ scroll-behavior: smooth;
+}
+
+/* Empêcher le scroll horizontal global */
body {
- margin: 0;
- padding: 0;
- display: flex;
- min-width: 320px;
- min-height: 100vh;
- width: 100%;
+ overflow-x: hidden;
}
-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;
+/* Styles pour les popups */
+.popup-content {
+ scrollbar-width: thin;
+ scrollbar-color: rgba(31, 93, 137, 0.3) transparent;
}
-button:hover {
- border-color: #646cff;
+.popup-content::-webkit-scrollbar {
+ width: 6px;
}
-button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
+.popup-content::-webkit-scrollbar-track {
+ background: transparent;
}
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- }
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
- }
+.popup-content::-webkit-scrollbar-thumb {
+ background: rgba(31, 93, 137, 0.3);
+ border-radius: 3px;
+}
+
+.popup-content::-webkit-scrollbar-thumb:hover {
+ background: rgba(31, 93, 137, 0.5);
+}
+
+/* Animation pour le bouton scroll to top */
+@keyframes bounce-up {
+ 0%, 100% { transform: translateY(0px); }
+ 50% { transform: translateY(-4px); }
+}
+
+.scroll-to-top:hover {
+ animation: bounce-up 0.6s ease-in-out;
}
diff --git a/banquise-website/src/main.tsx b/banquise-website/src/main.tsx
index bef5202..e3f1654 100644
--- a/banquise-website/src/main.tsx
+++ b/banquise-website/src/main.tsx
@@ -3,6 +3,18 @@ import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
+// Ajouter les métadonnées SEO
+document.title = 'La Banquise - Hébergement et Communauté Tech';
+const metaDescription = document.createElement('meta');
+metaDescription.name = 'description';
+metaDescription.content = 'Association d\'hébergement et lab réseau pour tous les étudiants et associations de l\'EPITA. Services Wiki, Gitea, Panel de jeux.';
+document.head.appendChild(metaDescription);
+
+const metaViewport = document.createElement('meta');
+metaViewport.name = 'viewport';
+metaViewport.content = 'width=device-width, initial-scale=1.0';
+document.head.appendChild(metaViewport);
+
createRoot(document.getElementById('root')!).render(
diff --git a/banquise-website/src/styles/components.ts b/banquise-website/src/styles/components.ts
new file mode 100644
index 0000000..48fcabf
--- /dev/null
+++ b/banquise-website/src/styles/components.ts
@@ -0,0 +1,63 @@
+export const commonStyles = {
+ // Gradients
+ gradients: {
+ primary: "bg-gradient-to-r from-banquise-blue to-banquise-blue-light",
+ primaryBr: "bg-gradient-to-br from-banquise-blue to-banquise-blue-light",
+ card: "bg-gradient-to-br from-banquise-blue-dark/10 to-banquise-blue-dark/5",
+ cardHover: "hover:from-banquise-blue-dark/15 hover:to-banquise-blue-dark/8",
+ discord: "bg-gradient-to-r from-indigo-600 to-purple-600",
+ discordHover: "hover:from-indigo-500 hover:to-purple-500"
+ },
+
+ // Buttons
+ buttons: {
+ primary: "inline-flex items-center justify-center font-bold text-white border-0 rounded-2xl transition-all duration-300 hover:shadow-xl hover:-translate-y-1 hover:scale-105 active:scale-95",
+ discord: "group relative overflow-hidden px-4 lg:px-6 py-2.5 lg:py-3 text-white font-semibold text-sm lg:text-base rounded-xl transition-all duration-300 hover:shadow-xl hover:shadow-indigo-500/25 hover:-translate-y-1 hover:scale-105",
+ auth: "group relative overflow-hidden px-4 lg:px-6 py-2.5 lg:py-3 text-white font-semibold text-sm lg:text-base rounded-xl transition-all duration-300 hover:shadow-xl hover:-translate-y-1 hover:scale-105"
+ },
+
+ // Cards
+ cards: {
+ base: "backdrop-blur-lg rounded-2xl border border-banquise-blue-lightest/30 transition-all duration-300",
+ hover: "hover:shadow-xl hover:border-banquise-blue-lightest/50",
+ interactive: "cursor-pointer hover:-translate-y-4 hover:shadow-2xl active:scale-95"
+ },
+
+ // Text - Hiérarchie améliorée
+ text: {
+ heading: "font-heading font-bold tracking-tight",
+ // Titres principaux de section
+ headingXl: "text-3xl sm:text-4xl md:text-5xl text-banquise-gray font-heading font-bold tracking-tight",
+ headingLg: "text-2xl sm:text-3xl md:text-4xl text-banquise-gray font-heading font-bold tracking-tight",
+ headingMd: "text-xl sm:text-2xl md:text-3xl text-banquise-blue-dark font-heading font-bold tracking-tight",
+ headingSm: "text-lg sm:text-xl md:text-2xl text-banquise-blue-dark font-heading font-semibold tracking-tight",
+ // Sous-titres
+ subheading: "text-base sm:text-lg md:text-xl text-banquise-gray/90 font-medium leading-relaxed",
+ // Corps de texte
+ body: "text-sm sm:text-base md:text-lg text-banquise-blue-dark/90 leading-relaxed",
+ description: "text-banquise-gray/80 leading-relaxed",
+ muted: "text-banquise-gray/90 leading-relaxed",
+ // Texte sur fond sombre
+ lightHeading: "text-banquise-blue-lightest font-heading font-bold tracking-tight",
+ lightBody: "text-white/90 leading-relaxed"
+ },
+
+ // Layout
+ layout: {
+ section: "py-12 sm:py-16 md:py-20 w-full max-w-6xl mx-auto px-4 sm:px-6 md:px-8",
+ container: "max-w-6xl mx-auto",
+ divider: "w-20 h-1 bg-gradient-to-r from-banquise-blue-lightest to-banquise-blue mx-auto mb-6 sm:mb-8 rounded-full"
+ },
+
+ // Icons and decorative elements
+ icons: {
+ base: "w-16 h-16 sm:w-20 sm:h-20 lg:w-24 lg:h-24 rounded-2xl flex items-center justify-center text-3xl sm:text-4xl lg:text-5xl shadow-lg",
+ small: "w-10 h-10 rounded-lg flex items-center justify-center text-white"
+ },
+
+ // Navigation
+ nav: {
+ link: "px-4 lg:px-6 py-2.5 lg:py-3 text-white/90 hover:text-white font-medium text-sm lg:text-base rounded-xl transition-all duration-300 hover:bg-white/10 hover:backdrop-blur-sm relative group",
+ mobileItem: "group flex items-center p-4 text-white/90 hover:text-white no-underline rounded-2xl hover:bg-gradient-to-r hover:from-banquise-blue/20 hover:to-banquise-blue-light/20 transition-all duration-300 border border-transparent hover:border-banquise-blue-lightest/20"
+ }
+} as const;
diff --git a/banquise-website/src/types/index.ts b/banquise-website/src/types/index.ts
new file mode 100644
index 0000000..3c8eb7a
--- /dev/null
+++ b/banquise-website/src/types/index.ts
@@ -0,0 +1,15 @@
+export interface Service {
+ name: string;
+ url: string;
+ image: string;
+ description: string;
+ features: string[];
+ icon: string;
+}
+
+export interface AccordionItemProps {
+ title: string;
+ children: React.ReactNode;
+ isOpen: boolean;
+ onToggle: () => void;
+}
diff --git a/banquise-website/tailwind.config.js b/banquise-website/tailwind.config.js
index 0bdb22b..724fe8a 100644
--- a/banquise-website/tailwind.config.js
+++ b/banquise-website/tailwind.config.js
@@ -7,11 +7,109 @@ export default {
theme: {
extend: {
colors: {
- // Vous pouvez personnaliser vos couleurs ici
+ banquise: {
+ blue: '#40B4FF',
+ 'blue-dark': '#1F5D89',
+ 'blue-light': '#69B7E2',
+ 'blue-lightest': '#A5F0FF',
+ gray: '#F6F6F6',
+ }
},
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, ')",
+ '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: [
diff --git a/shell.nix b/shell.nix
index 9c86acf..e63a99a 100644
--- a/shell.nix
+++ b/shell.nix
@@ -2,7 +2,7 @@
pkgs.mkShell {
buildInputs = [
- pkgs.nodejs_23
+ pkgs.nodejs_24
pkgs.nodePackages.tailwindcss
pkgs.nodePackages.postcss
pkgs.nodePackages.autoprefixer