Merge pull request 'UI FIX and Improvements' (#21) from sv-refactor into dev

Reviewed-on: #21
This commit is contained in:
Sahamone 2025-06-02 21:40:08 +02:00
commit 2d87e1d9b8
18 changed files with 628 additions and 203 deletions

View File

@ -6,6 +6,8 @@ import { TechFeaturesSection } from './components/sections/TechFeaturesSection';
import { ServicesSection } from './components/sections/ServicesSection'; import { ServicesSection } from './components/sections/ServicesSection';
import { AboutSection } from './components/sections/AboutSection'; import { AboutSection } from './components/sections/AboutSection';
import { Popup } from './components/ui/Popup'; import { Popup } from './components/ui/Popup';
import { ScrollToTopButton } from './components/ui/ScrollToTopButton';
import { URLS } from './config/constants';
// Define Service interface directly in App // Define Service interface directly in App
interface Service { interface Service {
@ -22,7 +24,7 @@ const App: React.FC = () => {
const services: Service[] = [ const services: Service[] = [
{ {
name: "Wiki", name: "Wiki",
url: "https://wiki.la-banquise.fr", url: URLS.services.wiki,
image: "/src/assets/iceberg.png", image: "/src/assets/iceberg.png",
icon: "📚", 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.", 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.",
@ -37,7 +39,7 @@ const App: React.FC = () => {
}, },
{ {
name: "Gitea", name: "Gitea",
url: "https://git.la-banquise.fr", url: URLS.services.gitea,
image: "/src/assets/iceberg.png", image: "/src/assets/iceberg.png",
icon: "🔧", 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.", 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.",
@ -52,7 +54,7 @@ const App: React.FC = () => {
}, },
{ {
name: "Panel", name: "Panel",
url: "https://panel.la-banquise.fr", url: URLS.services.panel,
image: "/src/assets/iceberg.png", image: "/src/assets/iceberg.png",
icon: "🎮", icon: "🎮",
description: "Interface de gestion centralisée pour vos serveurs de jeux. Déployez, configurez et surveillez vos serveurs gaming en quelques clics.", description: "Interface de gestion centralisée pour vos serveurs de jeux. Déployez, configurez et surveillez vos serveurs gaming en quelques clics.",
@ -91,6 +93,9 @@ const App: React.FC = () => {
<Footer /> <Footer />
{/* Bouton de retour en haut */}
<ScrollToTopButton />
{selectedService && ( {selectedService && (
<Popup service={selectedService} onClose={() => setSelectedService(null)} /> <Popup service={selectedService} onClose={() => setSelectedService(null)} />
)} )}

View File

@ -1,45 +1,46 @@
import React from 'react'; import React from 'react';
import { URLS, SITE_CONFIG } from '../../config/constants';
export const Footer: React.FC = () => ( export const Footer: React.FC = () => (
<footer className="bg-banquise-blue-dark text-white py-12 sm:py-16 md:py-20 px-4 sm:px-6 md:px-8 relative z-10 border-t border-banquise-blue-lightest/20 w-full box-border"> <footer className="bg-banquise-blue-dark text-white py-12 sm:py-16 md:py-20 px-4 sm:px-6 md:px-8 relative z-10 border-t border-banquise-blue-lightest/20 w-full box-border">
<div className="flex flex-col sm:flex-row sm:flex-wrap justify-between max-w-6xl mx-auto gap-6 sm:gap-8"> <div className="flex flex-col md:flex-row justify-between max-w-6xl mx-auto gap-6 sm:gap-8">
<div className="flex-1 min-w-48 sm:min-w-64 mb-6 sm:mb-8 text-left"> <div className="flex-1 min-w-0 mb-6 sm:mb-8 md:mb-0 text-left">
<h4 className="text-lg sm:text-xl mb-6 sm:mb-8 text-banquise-blue-lightest relative pb-3 sm:pb-4 after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-12 after:h-0.5 after:bg-gradient-to-r after:from-banquise-blue-lightest after:to-banquise-blue"> <h4 className="text-lg sm:text-xl mb-6 sm:mb-8 text-banquise-blue-lightest relative pb-3 sm:pb-4 after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-12 after:h-0.5 after:bg-gradient-to-r after:from-banquise-blue-lightest after:to-banquise-blue">
Services Services
</h4> </h4>
<ul className="list-none p-0 m-0 space-y-2 sm:space-y-3"> <ul className="list-none p-0 m-0 space-y-2 sm:space-y-3">
<li> <li>
<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 text-sm sm:text-base"> <a href={URLS.services.wiki} className="text-banquise-gray/80 no-underline transition-all duration-200 inline-flex items-center hover:text-banquise-gray hover:translate-x-1 text-sm sm:text-base">
Wiki Wiki
</a> </a>
</li> </li>
<li> <li>
<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 text-sm sm:text-base"> <a href={URLS.services.gitea} className="text-banquise-gray/80 no-underline transition-all duration-200 inline-flex items-center hover:text-banquise-gray hover:translate-x-1 text-sm sm:text-base">
Gitea Gitea
</a> </a>
</li> </li>
<li> <li>
<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 text-sm sm:text-base"> <a href={URLS.services.panel} className="text-banquise-gray/80 no-underline transition-all duration-200 inline-flex items-center hover:text-banquise-gray hover:translate-x-1 text-sm sm:text-base">
Panel Panel
</a> </a>
</li> </li>
</ul> </ul>
</div> </div>
<div className="flex-1 min-w-48 sm:min-w-64 mb-6 sm:mb-8 text-left"> <div className="flex-1 min-w-0 mb-6 sm:mb-8 md:mb-0 text-left">
<h4 className="text-lg sm:text-xl mb-6 sm:mb-8 text-banquise-blue-lightest relative pb-3 sm:pb-4 after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-12 after:h-0.5 after:bg-gradient-to-r after:from-banquise-blue-lightest after:to-banquise-blue"> <h4 className="text-lg sm:text-xl mb-6 sm:mb-8 text-banquise-blue-lightest relative pb-3 sm:pb-4 after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-12 after:h-0.5 after:bg-gradient-to-r after:from-banquise-blue-lightest after:to-banquise-blue">
Communauté Communauté
</h4> </h4>
<ul className="list-none p-0 m-0 space-y-2 sm:space-y-3"> <ul className="list-none p-0 m-0 space-y-2 sm:space-y-3">
<li> <li>
<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 text-sm sm:text-base"> <a href={URLS.social.discord} className="text-banquise-gray/80 no-underline transition-all duration-200 inline-flex items-center hover:text-banquise-gray hover:translate-x-1 text-sm sm:text-base">
Discord Discord
</a> </a>
</li> </li>
</ul> </ul>
</div> </div>
<div className="flex-1 min-w-48 sm:min-w-64 mb-6 sm:mb-8 text-left"> <div className="flex-1 min-w-0 mb-6 sm:mb-8 md:mb-0 text-left">
<h4 className="text-lg sm:text-xl mb-6 sm:mb-8 text-banquise-blue-lightest relative pb-3 sm:pb-4 after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-12 after:h-0.5 after:bg-gradient-to-r after:from-banquise-blue-lightest after:to-banquise-blue"> <h4 className="text-lg sm:text-xl mb-6 sm:mb-8 text-banquise-blue-lightest relative pb-3 sm:pb-4 after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-12 after:h-0.5 after:bg-gradient-to-r after:from-banquise-blue-lightest after:to-banquise-blue">
Support Support
</h4> </h4>
@ -50,7 +51,7 @@ export const Footer: React.FC = () => (
</a> </a>
</li> </li>
<li> <li>
<a href="mailto:contact@la-banquise.fr" className="text-banquise-gray/80 no-underline transition-all duration-200 inline-flex items-center hover:text-banquise-gray hover:translate-x-1 text-sm sm:text-base"> <a href={URLS.contact.email} className="text-banquise-gray/80 no-underline transition-all duration-200 inline-flex items-center hover:text-banquise-gray hover:translate-x-1 text-sm sm:text-base">
Contact Contact
</a> </a>
</li> </li>
@ -59,7 +60,7 @@ export const Footer: React.FC = () => (
</div> </div>
<div className="border-t border-banquise-blue-lightest/20 pt-6 sm:pt-8 mt-8 sm:mt-12 text-center text-xs sm:text-sm text-banquise-gray/70 max-w-6xl mx-auto"> <div className="border-t border-banquise-blue-lightest/20 pt-6 sm:pt-8 mt-8 sm:mt-12 text-center text-xs sm:text-sm text-banquise-gray/70 max-w-6xl mx-auto">
© 2024 La Banquise. Tous droits réservés. © 2024 {SITE_CONFIG.name}. Tous droits réservés.
</div> </div>
</footer> </footer>
); );

View File

@ -1,4 +1,7 @@
import React, { useEffect } from 'react'; 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 { interface MobileMenuProps {
isOpen: boolean; isOpen: boolean;
@ -6,7 +9,6 @@ interface MobileMenuProps {
} }
export const MobileMenu: React.FC<MobileMenuProps> = ({ isOpen, onClose }) => { export const MobileMenu: React.FC<MobileMenuProps> = ({ isOpen, onClose }) => {
// Empêcher le scroll du body quand le menu mobile est ouvert
useEffect(() => { useEffect(() => {
if (isOpen) { if (isOpen) {
document.body.style.overflow = 'hidden'; document.body.style.overflow = 'hidden';
@ -20,31 +22,31 @@ export const MobileMenu: React.FC<MobileMenuProps> = ({ isOpen, onClose }) => {
}, [isOpen]); }, [isOpen]);
return ( return (
<div className={`md:hidden fixed inset-0 z-40 transition-all duration-300 ${isOpen ? 'visible' : 'invisible'}`}> <div className={`md:hidden fixed inset-0 z-[100] transition-all duration-300 ${isOpen ? 'visible' : 'invisible'}`}>
{/* Overlay amélioré */} {/* Overlay */}
<div <div
className={`absolute inset-0 bg-gradient-to-br from-black/70 via-banquise-blue-dark/50 to-black/70 backdrop-blur-md transition-opacity duration-300 ${isOpen ? 'opacity-100' : 'opacity-0'}`} className={`absolute inset-0 bg-gradient-to-br from-black/70 via-banquise-blue-dark/50 to-black/70 backdrop-blur-md transition-opacity duration-300 ${isOpen ? 'opacity-100' : 'opacity-0'}`}
onClick={onClose} onClick={onClose}
/> />
{/* Menu mobile moderne */} {/* Menu mobile */}
<div className={`absolute top-0 right-0 h-full w-80 max-w-[90vw] bg-gradient-to-b from-banquise-blue-dark via-banquise-blue-dark/98 to-banquise-blue-dark/95 backdrop-blur-2xl shadow-2xl transition-transform duration-300 border-l border-banquise-blue-lightest/20 ${isOpen ? 'translate-x-0' : 'translate-x-full'}`}> <div className={`absolute top-0 right-0 h-full w-72 max-w-[85vw] bg-gradient-to-b from-banquise-blue-dark via-banquise-blue-dark/98 to-banquise-blue-dark/95 backdrop-blur-2xl shadow-2xl transition-transform duration-300 border-l border-banquise-blue-lightest/20 ${isOpen ? 'translate-x-0' : 'translate-x-full'}`}>
{/* Header moderne */} {/* Header */}
<div className="flex items-center justify-between p-6 border-b border-banquise-blue-lightest/20 bg-gradient-to-r from-banquise-blue-dark/50 to-transparent"> <div className="flex items-center justify-between p-4 sm:p-6 pt-6 sm:pt-8 border-b border-banquise-blue-lightest/20 bg-gradient-to-r from-banquise-blue-dark/50 to-transparent">
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<div className="relative"> <div className="relative">
<div className="absolute inset-0 bg-banquise-blue-light/20 rounded-full blur-md"></div> <div className="absolute inset-0 bg-banquise-blue-light/20 rounded-full blur-md"></div>
<img <img
src="/src/assets/banquise.png" src={banquiseServer}
alt="Logo" alt="Logo"
className="h-10 w-auto relative z-10" className="h-8 sm:h-10 w-auto relative z-10"
style={{ filter: 'drop-shadow(0 0 8px rgba(168, 218, 255, 0.6))' }} style={{ filter: 'drop-shadow(0 0 8px rgba(168, 218, 255, 0.6))' }}
/> />
</div> </div>
<div> <div>
<span className="text-lg font-bold text-white font-heading"> <span className={`text-base sm:text-lg font-bold text-white ${commonStyles.text.heading}`}>
La Banquise {SITE_CONFIG.name}
</span> </span>
<p className="text-banquise-blue-lightest/70 text-xs">Menu Navigation</p> <p className="text-banquise-blue-lightest/70 text-xs">Menu Navigation</p>
</div> </div>
@ -61,18 +63,14 @@ export const MobileMenu: React.FC<MobileMenuProps> = ({ isOpen, onClose }) => {
</button> </button>
</div> </div>
{/* Navigation moderne */} {/* Navigation */}
<div className="flex flex-col justify-center px-6 py-8 space-y-6"> <div className="flex flex-col justify-start px-6 py-8 space-y-6 overflow-y-auto" style={{ height: 'calc(100vh - 120px)' }}>
{/* Navigation Links */} {/* Navigation Links */}
<div className="space-y-3"> <div className="space-y-3">
<a <a href="#services" className={commonStyles.nav.mobileItem} onClick={onClose}>
href="#services"
className="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"
onClick={onClose}
>
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<div className="w-10 h-10 bg-gradient-to-br from-banquise-blue to-banquise-blue-light rounded-xl flex items-center justify-center group-hover:scale-110 transition-transform duration-200"> <div className={`${commonStyles.icons.small} ${commonStyles.gradients.primaryBr} group-hover:scale-110 transition-transform duration-200`}>
<svg className="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg className="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
</svg> </svg>
@ -87,13 +85,9 @@ export const MobileMenu: React.FC<MobileMenuProps> = ({ isOpen, onClose }) => {
</svg> </svg>
</a> </a>
<a <a href="#about" className={commonStyles.nav.mobileItem} onClick={onClose}>
href="#about"
className="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"
onClick={onClose}
>
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<div className="w-10 h-10 bg-gradient-to-br from-banquise-blue to-banquise-blue-light rounded-xl flex items-center justify-center group-hover:scale-110 transition-transform duration-200"> <div className={`${commonStyles.icons.small} ${commonStyles.gradients.primaryBr} group-hover:scale-110 transition-transform duration-200`}>
<svg className="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg className="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg> </svg>
@ -108,13 +102,9 @@ export const MobileMenu: React.FC<MobileMenuProps> = ({ isOpen, onClose }) => {
</svg> </svg>
</a> </a>
<a <a href={URLS.social.discord} className={commonStyles.nav.mobileItem} onClick={onClose}>
href="https://discord.gg/labanquise"
className="group flex items-center p-4 text-white/90 hover:text-white no-underline rounded-2xl hover:bg-gradient-to-r hover:from-indigo-600/20 hover:to-purple-600/20 transition-all duration-300 border border-transparent hover:border-indigo-400/20"
onClick={onClose}
>
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<div className="w-10 h-10 bg-gradient-to-br from-indigo-600 to-purple-600 rounded-xl flex items-center justify-center group-hover:scale-110 transition-transform duration-200"> <div className={`${commonStyles.icons.small} ${commonStyles.gradients.discord} group-hover:scale-110 transition-transform duration-200`}>
<svg className="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 24 24"> <svg className="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.211.375-.445.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03z"/> <path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.211.375-.445.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03z"/>
</svg> </svg>
@ -133,10 +123,10 @@ export const MobileMenu: React.FC<MobileMenuProps> = ({ isOpen, onClose }) => {
{/* CTA Button */} {/* CTA Button */}
<div className="pt-6 border-t border-banquise-blue-lightest/20"> <div className="pt-6 border-t border-banquise-blue-lightest/20">
<a <a
href="https://auth.la-banquise.fr" href={URLS.services.auth}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="w-full flex items-center justify-center bg-gradient-to-r from-banquise-blue to-banquise-blue-light text-white border-0 py-4 px-6 rounded-2xl cursor-pointer no-underline font-bold text-lg shadow-xl transition-all duration-300 hover:shadow-2xl hover:scale-105 active:scale-95 border border-banquise-blue-lightest/20" className={`w-full ${commonStyles.buttons.primary} ${commonStyles.gradients.primary} py-4 px-6 text-lg shadow-xl border border-banquise-blue-lightest/20`}
onClick={onClose} onClick={onClose}
> >
<svg className="w-6 h-6 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg className="w-6 h-6 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@ -147,11 +137,11 @@ export const MobileMenu: React.FC<MobileMenuProps> = ({ isOpen, onClose }) => {
</div> </div>
</div> </div>
{/* Footer simplifié */} {/* Footer */}
<div className="absolute bottom-6 left-6 right-6"> <div className="absolute bottom-6 left-6 right-6">
<div className="text-center py-4 border-t border-banquise-blue-lightest/20"> <div className="text-center py-4 border-t border-banquise-blue-lightest/20">
<p className="text-white/50 text-sm"> <p className="text-white/50 text-sm">
© 2024 La Banquise © 2024 {SITE_CONFIG.name}
</p> </p>
</div> </div>
</div> </div>

View File

@ -1,12 +1,13 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { MobileMenu } from './MobileMenu'; import { MobileMenu } from './MobileMenu';
import banquiseServer from '/src/assets/banquise_server.svg' 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 = () => { export const Navigation: React.FC = () => {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const [scrolled, setScrolled] = useState(false); const [scrolled, setScrolled] = useState(false);
// Gérer l'effet de scroll sur la navbar
useEffect(() => { useEffect(() => {
const handleScroll = () => { const handleScroll = () => {
const isScrolled = window.scrollY > 20; const isScrolled = window.scrollY > 20;
@ -17,7 +18,6 @@ export const Navigation: React.FC = () => {
return () => window.removeEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll);
}, []); }, []);
// Fermer le menu mobile quand on redimensionne la fenêtre
useEffect(() => { useEffect(() => {
const handleResize = () => { const handleResize = () => {
if (window.innerWidth >= 768) { if (window.innerWidth >= 768) {
@ -36,8 +36,8 @@ export const Navigation: React.FC = () => {
? 'bg-banquise-blue-dark/98 backdrop-blur-xl shadow-2xl border-b border-banquise-blue-lightest/30' ? 'bg-banquise-blue-dark/98 backdrop-blur-xl shadow-2xl border-b border-banquise-blue-lightest/30'
: 'bg-banquise-blue-dark/95 backdrop-blur-lg shadow-xl border-b border-banquise-blue-lightest/20' : 'bg-banquise-blue-dark/95 backdrop-blur-lg shadow-xl border-b border-banquise-blue-lightest/20'
}`}> }`}>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className={commonStyles.layout.container}>
<div className="flex justify-between items-center h-16 sm:h-18 lg:h-20"> <div className="flex justify-between items-center h-16 sm:h-18 lg:h-20 px-4 sm:px-6 lg:px-8">
{/* Logo section */} {/* Logo section */}
<div className="flex items-center space-x-3 sm:space-x-4 group"> <div className="flex items-center space-x-3 sm:space-x-4 group">
@ -51,29 +51,23 @@ export const Navigation: React.FC = () => {
/> />
</div> </div>
<div className="hidden sm:block"> <div className="hidden sm:block">
<h1 className="text-xl sm:text-2xl lg:text-3xl font-bold text-white tracking-wide font-heading"> <h1 className={`text-xl sm:text-2xl lg:text-3xl font-bold text-white tracking-wide ${commonStyles.text.heading}`}>
La Banquise {SITE_CONFIG.name}
</h1> </h1>
<p className="text-banquise-blue-lightest/80 text-xs lg:text-sm font-medium"> <p className="text-banquise-blue-lightest/80 text-xs lg:text-sm font-medium">
Communauté Hébergement {SITE_CONFIG.tagline}
</p> </p>
</div> </div>
</div> </div>
{/* Navigation links desktop */} {/* Navigation links desktop */}
<div className="hidden md:flex items-center space-x-1 lg:space-x-2"> <div className="hidden md:flex items-center space-x-1 lg:space-x-2">
<a <a href="#services" className={commonStyles.nav.link}>
href="#services"
className="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"
>
<span className="relative z-10">Services</span> <span className="relative z-10">Services</span>
<div className="absolute inset-0 bg-gradient-to-r from-banquise-blue-light/20 to-banquise-blue/20 rounded-xl opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div> <div className="absolute inset-0 bg-gradient-to-r from-banquise-blue-light/20 to-banquise-blue/20 rounded-xl opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
</a> </a>
<a <a href="#about" className={commonStyles.nav.link}>
href="#about"
className="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"
>
<span className="relative z-10">À propos</span> <span className="relative z-10">À propos</span>
<div className="absolute inset-0 bg-gradient-to-r from-banquise-blue-light/20 to-banquise-blue/20 rounded-xl opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div> <div className="absolute inset-0 bg-gradient-to-r from-banquise-blue-light/20 to-banquise-blue/20 rounded-xl opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
</a> </a>
@ -82,12 +76,12 @@ export const Navigation: React.FC = () => {
{/* Action buttons desktop */} {/* Action buttons desktop */}
<div className="hidden md:flex items-center space-x-3 lg:space-x-4"> <div className="hidden md:flex items-center space-x-3 lg:space-x-4">
<a <a
href="https://discord.gg/labanquise" href={URLS.social.discord}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="group relative overflow-hidden px-4 lg:px-6 py-2.5 lg:py-3 bg-gradient-to-r from-indigo-600 to-purple-600 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" className={`${commonStyles.buttons.discord} ${commonStyles.gradients.discord}`}
> >
<div className="absolute inset-0 bg-gradient-to-r from-indigo-500 to-purple-500 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div> <div className={`absolute inset-0 ${commonStyles.gradients.discordHover} opacity-0 group-hover:opacity-100 transition-opacity duration-300`}></div>
<div className="relative z-10 flex items-center space-x-2"> <div className="relative z-10 flex items-center space-x-2">
<svg className="w-4 h-4 lg:w-5 lg:h-5" fill="currentColor" viewBox="0 0 24 24"> <svg className="w-4 h-4 lg:w-5 lg:h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.211.375-.445.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03z"/> <path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.211.375-.445.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03z"/>
@ -97,12 +91,12 @@ export const Navigation: React.FC = () => {
</a> </a>
<a <a
href="https://auth.la-banquise.fr" href={URLS.services.auth}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className={`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 ${ className={`${commonStyles.buttons.auth} ${
scrolled scrolled
? 'bg-gradient-to-r from-banquise-blue to-banquise-blue-light border border-banquise-blue-lightest/30 hover:shadow-banquise-blue/25' ? `${commonStyles.gradients.primary} border border-banquise-blue-lightest/30 hover:shadow-banquise-blue/25`
: 'bg-gradient-to-r from-banquise-blue-light to-banquise-blue border-2 border-white/20 hover:shadow-banquise-blue-light/25' : 'bg-gradient-to-r from-banquise-blue-light to-banquise-blue border-2 border-white/20 hover:shadow-banquise-blue-light/25'
}`} }`}
> >

View File

@ -1,5 +1,7 @@
import React from 'react'; import React from 'react';
import { AccordionItem } from '../ui/AccordionItem'; import { AccordionItem } from '../ui/AccordionItem';
import { URLS } from '../../config/constants';
import { commonStyles } from '../../styles/components';
interface AboutSectionProps { interface AboutSectionProps {
openAccordion: string | null; openAccordion: string | null;
@ -11,18 +13,18 @@ export const AboutSection: React.FC<AboutSectionProps> = ({ openAccordion, toggl
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
{/* Header */} {/* Header */}
<div className="text-center mb-12 sm:mb-16 md:mb-20"> <div className="text-center mb-12 sm:mb-16 md:mb-20">
<div className="w-20 h-1 bg-gradient-to-r from-banquise-blue-lightest to-banquise-blue mx-auto mb-6 sm:mb-8 rounded-full"></div> <div className={commonStyles.layout.divider}></div>
<h2 className="text-banquise-gray text-2xl sm:text-3xl md:text-4xl mb-6 sm:mb-8 font-heading font-bold tracking-tight px-2" style={{ textShadow: '0 2px 4px rgba(0, 0, 0, 0.2)' }}> <h2 className={`${commonStyles.text.headingXl} mb-6 sm:mb-8 px-2`} style={{ textShadow: '0 2px 4px rgba(0, 0, 0, 0.2)' }}>
À Propos de La Banquise À Propos de La Banquise
</h2> </h2>
<p className="text-banquise-gray/90 text-lg sm:text-xl max-w-3xl mx-auto leading-relaxed px-2" style={{ textShadow: '0 1px 2px rgba(0, 0, 0, 0.1)' }}> <p className={`${commonStyles.text.muted} text-lg sm:text-xl max-w-3xl mx-auto px-2`} style={{ textShadow: '0 1px 2px rgba(0, 0, 0, 0.1)' }}>
Une communauté passionnée qui propose des services d'hébergement et des outils collaboratifs pour les développeurs et les gamers. Une communauté passionnée qui propose des services d'hébergement et des outils collaboratifs pour les développeurs et les gamers.
</p> </p>
</div> </div>
{/* FAQ Section */} {/* FAQ Section */}
<div className="space-y-4 sm:space-y-6"> <div className="space-y-4 sm:space-y-6">
<h3 className="text-xl sm:text-2xl font-bold text-banquise-gray mb-8 sm:mb-12 font-heading flex items-center justify-center px-2"> <h3 className={`${commonStyles.text.headingLg} mb-8 sm:mb-12 flex items-center justify-center px-2`}>
<span className="text-2xl sm:text-3xl mr-3"></span> <span className="text-2xl sm:text-3xl mr-3"></span>
<span className="text-center">Questions Fréquentes</span> <span className="text-center">Questions Fréquentes</span>
</h3> </h3>
@ -33,11 +35,11 @@ export const AboutSection: React.FC<AboutSectionProps> = ({ openAccordion, toggl
onToggle={() => toggleAccordion("mission")} onToggle={() => toggleAccordion("mission")}
> >
<div className="space-y-4"> <div className="space-y-4">
<p className="text-banquise-gray/90 leading-relaxed"> <p className={commonStyles.text.muted}>
Former les étudiants au déploiment et a la gestion d'une infra, et de maitriser des technologies entreprise grade. 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 ! Cela permet de fournir une plateforme stable et accessible pour héberger vos projets, partager vos connaissances et jouer ensemble !
</p> </p>
<p className="text-banquise-gray/90 leading-relaxed"> <p className={commonStyles.text.muted}>
Nous croyons en la puissance de la collaboration et mettons à disposition des outils modernes pour faciliter le travail en équipe. Nous croyons en la puissance de la collaboration et mettons à disposition des outils modernes pour faciliter le travail en équipe.
</p> </p>
<div className="flex flex-wrap gap-2 mt-4"> <div className="flex flex-wrap gap-2 mt-4">
@ -55,31 +57,31 @@ export const AboutSection: React.FC<AboutSectionProps> = ({ openAccordion, toggl
> >
<div className="space-y-6"> <div className="space-y-6">
<div className="grid gap-4"> <div className="grid gap-4">
<div className="flex items-start space-x-4 p-4 bg-banquise-blue-dark/10 rounded-xl border border-banquise-blue-lightest/20"> <div className={`flex items-start space-x-4 p-4 ${commonStyles.gradients.card} rounded-xl ${commonStyles.cards.base}`}>
<div className="w-10 h-10 bg-gradient-to-br from-banquise-blue to-banquise-blue-light rounded-lg flex items-center justify-center text-white font-bold">📚</div> <div className={`${commonStyles.icons.small} ${commonStyles.gradients.primaryBr} font-bold`}>📚</div>
<div> <div>
<h4 className="font-semibold text-banquise-gray mb-1">Wiki</h4> <h4 className="font-semibold text-banquise-gray mb-1">Wiki</h4>
<p className="text-banquise-gray/80 text-sm">Documentation collaborative et guides détaillés</p> <p className="text-banquise-gray/80 text-sm">Documentation collaborative et guides détaillés</p>
</div> </div>
</div> </div>
<div className="flex items-start space-x-4 p-4 bg-banquise-blue-dark/10 rounded-xl border border-banquise-blue-lightest/20"> <div className={`flex items-start space-x-4 p-4 ${commonStyles.gradients.card} rounded-xl ${commonStyles.cards.base}`}>
<div className="w-10 h-10 bg-gradient-to-br from-banquise-blue to-banquise-blue-light rounded-lg flex items-center justify-center text-white font-bold">🔧</div> <div className={`${commonStyles.icons.small} ${commonStyles.gradients.primaryBr} font-bold`}>🔧</div>
<div> <div>
<h4 className="font-semibold text-banquise-gray mb-1">Gitea</h4> <h4 className="font-semibold text-banquise-gray mb-1">Gitea</h4>
<p className="text-banquise-gray/80 text-sm">Gestion de versions Git auto-hébergée</p> <p className="text-banquise-gray/80 text-sm">Gestion de versions Git auto-hébergée</p>
</div> </div>
</div> </div>
<div className="flex items-start space-x-4 p-4 bg-banquise-blue-dark/10 rounded-xl border border-banquise-blue-lightest/20"> <div className={`flex items-start space-x-4 p-4 ${commonStyles.gradients.card} rounded-xl ${commonStyles.cards.base}`}>
<div className="w-10 h-10 bg-gradient-to-br from-banquise-blue to-banquise-blue-light rounded-lg flex items-center justify-center text-white font-bold">🎮</div> <div className={`${commonStyles.icons.small} ${commonStyles.gradients.primaryBr} font-bold`}>🎮</div>
<div> <div>
<h4 className="font-semibold text-banquise-gray mb-1">Panel de Jeux</h4> <h4 className="font-semibold text-banquise-gray mb-1">Panel de Jeux</h4>
<p className="text-banquise-gray/80 text-sm">Interface de gestion pour serveurs de jeux</p> <p className="text-banquise-gray/80 text-sm">Interface de gestion pour serveurs de jeux</p>
</div> </div>
</div> </div>
</div> </div>
<p className="text-banquise-gray/90 leading-relaxed mt-4"> <p className={`${commonStyles.text.muted} mt-4`}>
Tous nos services sont maintenus avec soin et régulièrement mis à jour pour garantir une expérience optimale. Tous nos services sont maintenus avec soin et régulièrement mis à jour pour garantir une expérience optimale.
</p> </p>
</div> </div>
@ -91,11 +93,11 @@ export const AboutSection: React.FC<AboutSectionProps> = ({ openAccordion, toggl
onToggle={() => toggleAccordion("community")} onToggle={() => toggleAccordion("community")}
> >
<div className="space-y-6"> <div className="space-y-6">
<p className="text-banquise-gray/90 leading-relaxed"> <p className={commonStyles.text.muted}>
Rejoignez notre serveur Discord pour rejoindre l'asso, échanger avec nous, obtenir de l'aide et rester informé des dernières nouveautés ! Rejoignez notre serveur Discord pour rejoindre l'asso, échanger avec nous, obtenir de l'aide et rester informé des dernières nouveautés !
</p> </p>
<div className="bg-gradient-to-r from-banquise-blue-dark/20 to-banquise-blue/10 rounded-2xl p-6 border border-banquise-blue-lightest/30"> <div className={`${commonStyles.cards.base} bg-gradient-to-r from-banquise-blue-dark/20 to-banquise-blue/10 rounded-2xl p-6`}>
<h4 className="font-semibold text-banquise-gray mb-3 flex items-center"> <h4 className="font-semibold text-banquise-gray mb-3 flex items-center">
<span className="text-xl mr-2">💬</span> <span className="text-xl mr-2">💬</span>
Comment rejoindre l'asso ? Comment rejoindre l'asso ?
@ -107,8 +109,8 @@ export const AboutSection: React.FC<AboutSectionProps> = ({ openAccordion, toggl
</ul> </ul>
<a <a
href="https://discord.gg/labanquise" href={URLS.social.discord}
className="inline-flex items-center bg-gradient-to-r from-banquise-blue to-banquise-blue-light text-white border-0 py-3 px-6 rounded-xl no-underline font-bold transition-all duration-300 hover:shadow-lg hover:-translate-y-1 hover:scale-105" className={`${commonStyles.buttons.primary} ${commonStyles.gradients.primary} py-3 px-6 rounded-xl`}
> >
<span className="mr-3 text-lg">🚀</span> <span className="mr-3 text-lg">🚀</span>
Rejoindre Discord Rejoindre Discord

View File

@ -3,21 +3,28 @@ import banquiseServer from '/src/assets/banquise_server.svg'
export const HeroSection: React.FC = () => ( export const HeroSection: React.FC = () => (
<section className="min-h-[calc(80vh-72px)] flex flex-col justify-center items-center text-center py-12 sm:py-16 md:py-20 w-full max-w-6xl mx-auto px-4 sm:px-6 md:px-8 relative z-3"> <section className="min-h-[calc(80vh-72px)] flex flex-col justify-center items-center text-center py-12 sm:py-16 md:py-20 w-full max-w-6xl mx-auto px-4 sm:px-6 md:px-8 relative z-3">
<div className="mb-8 sm:mb-10 md:mb-12 w-32 h-32 sm:w-40 sm:h-40 md:w-48 md:h-48 rounded-full bg-gradient-to-br from-banquise-blue-dark/20 to-banquise-blue/10 p-4 sm:p-5 md:p-6 shadow-2xl animate-gentle-float backdrop-blur-sm border border-banquise-blue-lightest/30"> <div className="mb-8 sm:mb-10 md:mb-12 w-32 h-32 sm:w-40 sm:h-40 md:w-48 md:h-48 rounded-full bg-gradient-to-br from-banquise-blue-dark/20 to-banquise-blue/10 p-4 sm:p-5 md:p-6 shadow-2xl backdrop-blur-sm border border-banquise-blue-lightest/30 relative group">
<img src={banquiseServer} alt="Logo La Banquise" className="w-full h-full object-contain" style={{ filter: 'drop-shadow(0 10px 25px rgba(31, 93, 137, 0.3))' }} /> <img
src={banquiseServer}
alt="Logo La Banquise"
className="w-full h-full object-contain relative z-10 transition-transform duration-300 group-hover:scale-110"
style={{
filter: 'drop-shadow(0 10px 25px rgba(31, 93, 137, 0.3))'
}}
/>
</div> </div>
<h1 className="text-banquise-gray text-3xl sm:text-4xl md:text-5xl lg:text-6xl mb-6 sm:mb-7 md:mb-8 font-extrabold leading-tight max-w-4xl font-heading px-2" style={{ textShadow: '0 2px 10px rgba(0, 0, 0, 0.3)' }}> <h1 className="text-banquise-gray text-3xl sm:text-4xl md:text-5xl lg:text-6xl mb-6 sm:mb-7 md:mb-8 font-extrabold leading-tight max-w-4xl font-heading px-2 relative z-10" style={{ textShadow: '0 2px 10px rgba(0, 0, 0, 0.3)' }}>
Bienvenue sur La Banquise Bienvenue sur La Banquise
</h1> </h1>
<p className="text-banquise-gray text-lg sm:text-xl md:text-2xl mb-8 sm:mb-10 md:mb-12 max-w-3xl font-normal opacity-90 leading-relaxed px-2" style={{ textShadow: '0 1px 4px rgba(0, 0, 0, 0.2)' }}> <p className="text-banquise-gray text-lg sm:text-xl md:text-2xl mb-8 sm:mb-10 md:mb-12 max-w-3xl font-normal opacity-90 leading-relaxed px-2 relative z-10" style={{ textShadow: '0 1px 4px rgba(0, 0, 0, 0.2)' }}>
Association d'hébergement et lab réseau pour tous les étudiants et associations de l'EPITA ! Association d'hébergement et lab réseau pour tous les étudiants et associations de l'EPITA !
</p> </p>
<a href="#services" className="inline-flex items-center justify-center bg-gradient-to-r from-banquise-gray to-white text-banquise-blue-dark border-0 py-4 sm:py-5 px-8 sm:px-10 md:px-12 rounded-2xl text-base sm:text-lg font-bold no-underline shadow-xl transition-all duration-300 min-w-48 sm:min-w-56 md:min-w-64 hover:-translate-y-2 hover:shadow-2xl hover:scale-105 backdrop-blur-sm border border-banquise-blue-lightest/20 mx-4"> <a href="#services" className="inline-flex items-center justify-center bg-gradient-to-r from-banquise-gray to-white text-banquise-blue-dark border-0 py-4 sm:py-5 px-8 sm:px-10 md:px-12 rounded-2xl text-base sm:text-lg font-bold no-underline shadow-xl transition-all duration-300 min-w-48 sm:min-w-56 md:min-w-64 hover:-translate-y-2 hover:shadow-2xl hover:scale-105 backdrop-blur-sm border border-banquise-blue-lightest/20 mx-4 group relative z-10">
<span className="text-center">Découvrir nos services</span> <span className="text-center text-banquise-blue-dark">Découvrir nos services</span>
<span className="ml-2 sm:ml-3 text-lg sm:text-xl transition-transform duration-300 group-hover:translate-x-1"></span> <span className="ml-2 sm:ml-3 text-lg sm:text-xl transition-transform duration-300 group-hover:translate-x-1 text-banquise-blue-dark"></span>
</a> </a>
</section> </section>
); );

View File

@ -1,15 +1,16 @@
import React from 'react'; import React from 'react';
// Define interface directly in the component file // Declare the Service interface here
interface Service { interface Service {
name: string; name: string;
url: string; url: string;
image: string; image: string;
icon: string;
description: string; description: string;
features: string[]; features: string[];
icon: string;
} }
// Define interface directly in the component file
interface ServicesSectionProps { interface ServicesSectionProps {
services: Service[]; services: Service[];
onServiceClick: (service: Service) => void; onServiceClick: (service: Service) => void;

View File

@ -10,7 +10,7 @@ export const TechFeaturesSection: React.FC = () => (
25+ serveurs pour répondre à vos besoins 25+ serveurs pour répondre à vos besoins
</p> </p>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6 w-full"> <div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-4 sm:gap-6 w-full">
<div className="bg-gradient-to-br from-banquise-blue-dark/10 to-banquise-blue-dark/5 backdrop-blur-lg rounded-2xl p-6 sm:p-8 flex flex-col items-center text-center transition-all duration-300 border border-banquise-blue-lightest/30 hover:-translate-y-3 hover:from-banquise-blue-dark/15 hover:to-banquise-blue-dark/8 hover:shadow-xl hover:border-banquise-blue-lightest/50 group"> <div className="bg-gradient-to-br from-banquise-blue-dark/10 to-banquise-blue-dark/5 backdrop-blur-lg rounded-2xl p-6 sm:p-8 flex flex-col items-center text-center transition-all duration-300 border border-banquise-blue-lightest/30 hover:-translate-y-3 hover:from-banquise-blue-dark/15 hover:to-banquise-blue-dark/8 hover:shadow-xl hover:border-banquise-blue-lightest/50 group">
<div className="text-3xl sm:text-4xl mb-4 sm:mb-6 text-white bg-gradient-to-br from-banquise-blue to-banquise-blue-light w-16 h-16 sm:w-20 sm:h-20 flex items-center justify-center rounded-2xl shadow-lg group-hover:scale-110 transition-transform duration-300"> <div className="text-3xl sm:text-4xl mb-4 sm:mb-6 text-white bg-gradient-to-br from-banquise-blue to-banquise-blue-light w-16 h-16 sm:w-20 sm:h-20 flex items-center justify-center rounded-2xl shadow-lg group-hover:scale-110 transition-transform duration-300">
🚀 🚀

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
// Define interface directly in the component file // Définir l'interface localement :
interface AccordionItemProps { interface AccordionItemProps {
title: string; title: string;
children: React.ReactNode; children: React.ReactNode;
@ -14,7 +14,7 @@ export const AccordionItem: React.FC<AccordionItemProps> = ({ title, children, i
className="p-4 sm:p-6 md:p-8 cursor-pointer flex items-center justify-between font-semibold text-banquise-gray transition-all duration-200 text-base sm:text-lg select-none hover:bg-banquise-blue-dark/10 active:bg-banquise-blue-dark/15" className="p-4 sm:p-6 md:p-8 cursor-pointer flex items-center justify-between font-semibold text-banquise-gray transition-all duration-200 text-base sm:text-lg select-none hover:bg-banquise-blue-dark/10 active:bg-banquise-blue-dark/15"
onClick={onToggle} onClick={onToggle}
> >
<span className="flex items-center flex-1 mr-4">{title}</span> <span className="flex items-center flex-1 mr-4 font-heading">{title}</span>
<span className={`text-xl sm:text-2xl transition-transform duration-300 text-banquise-blue-lightest flex-shrink-0 ${isOpen ? 'rotate-180' : ''}`}> <span className={`text-xl sm:text-2xl transition-transform duration-300 text-banquise-blue-lightest flex-shrink-0 ${isOpen ? 'rotate-180' : ''}`}>
</span> </span>

View File

@ -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 (
<div className="fixed inset-0 pointer-events-none overflow-hidden z-0">
{/* Grille de fond subtile */}
<div className="absolute inset-0 opacity-[0.02]">
<div
className="absolute inset-0 bg-gradient-to-br from-banquise-blue-dark/20 to-transparent"
style={{
backgroundImage: `
linear-gradient(rgba(31, 93, 137, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(31, 93, 137, 0.03) 1px, transparent 1px)
`,
backgroundSize: '50px 50px',
transform: `translateY(${scrollY * 0.1}px)`
}}
/>
</div>
{/* Particules de code flottantes */}
<div className="absolute inset-0">
{floatingElements.map((element, index) => (
<div
key={index}
className={`absolute ${element.size} font-mono select-none transition-all duration-1000 ease-out`}
style={{
left: `${element.x}%`,
top: `${element.y}%`,
transform: `translateY(${scrollY * element.speed}px) rotate(${scrollY * 0.01}deg)`,
opacity: element.opacity,
color: element.isText ? '#a8daff' : 'inherit',
textShadow: element.isText ? '0 0 10px rgba(168, 218, 255, 0.3)' : 'none',
filter: 'blur(0.5px)',
animation: `float-${index % 3} ${6 + (index % 4)}s ease-in-out infinite`
}}
>
{element.icon}
</div>
))}
</div>
{/* Lignes de connexion animées */}
<svg
className="absolute inset-0 w-full h-full opacity-[0.03]"
style={{
transform: `translateY(${scrollY * 0.2}px)`
}}
>
<defs>
<linearGradient id="lineGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stopColor="#a8daff" stopOpacity="0" />
<stop offset="50%" stopColor="#a8daff" stopOpacity="0.5" />
<stop offset="100%" stopColor="#a8daff" stopOpacity="0" />
</linearGradient>
</defs>
{/* Lignes de connexion entre les éléments */}
{[...Array(8)].map((_, i) => (
<line
key={i}
x1={`${10 + i * 12}%`}
y1={`${20 + i * 8}%`}
x2={`${30 + i * 15}%`}
y2={`${40 + i * 12}%`}
stroke="url(#lineGradient)"
strokeWidth="1"
className="animate-pulse"
style={{
animationDelay: `${i * 0.5}s`,
animationDuration: `${3 + i}s`
}}
/>
))}
</svg>
{/* Cercles de données en mouvement */}
<div className="absolute inset-0">
{[...Array(6)].map((_, i) => (
<div
key={i}
className="absolute rounded-full border border-banquise-blue-lightest/5 animate-ping"
style={{
left: `${15 + i * 15}%`,
top: `${25 + i * 12}%`,
width: `${40 + i * 20}px`,
height: `${40 + i * 20}px`,
transform: `translateY(${scrollY * (0.1 + i * 0.05)}px)`,
animationDelay: `${i * 1.2}s`,
animationDuration: `${4 + i}s`
}}
/>
))}
</div>
</div>
);
};

View File

@ -1,13 +1,13 @@
import React from 'react'; import React, { useEffect } from 'react';
import { URLS } from '../../config/constants';
// Define interface directly in the component file
interface Service { interface Service {
name: string; name: string;
url: string; url: string;
image: string; image: string;
icon: string;
description: string; description: string;
features: string[]; features: string[];
icon: string;
} }
interface PopupProps { interface PopupProps {
@ -15,110 +15,127 @@ interface PopupProps {
onClose: () => void; onClose: () => void;
} }
export const Popup: React.FC<PopupProps> = ({ service, onClose }) => ( export const Popup: React.FC<PopupProps> = ({ service, onClose }) => {
<div className="fixed inset-0 bg-black/60 flex justify-center items-center z-50 p-4 backdrop-blur-md animate-fadeIn"> // Empêcher le scroll du body quand la popup est ouverte
<div className="bg-white text-banquise-blue-dark rounded-3xl max-w-5xl w-full max-h-[90vh] overflow-y-auto shadow-2xl relative animate-slideUp border border-banquise-blue-lightest/20"> useEffect(() => {
document.body.style.overflow = 'hidden';
{/* Header */}
<div className="relative bg-gradient-to-r from-banquise-blue to-banquise-blue-light p-6 sm:p-8 text-white"> return () => {
<button document.body.style.overflow = 'unset';
onClick={onClose} };
className="absolute top-4 sm:top-6 right-4 sm:right-6 bg-white/20 hover:bg-white/30 border-0 text-xl sm:text-2xl cursor-pointer text-white flex items-center justify-center w-10 h-10 sm:w-12 sm:h-12 rounded-full transition-all duration-200 backdrop-blur-sm hover:scale-110 active:scale-95" }, []);
>
× return (
</button> <div className="fixed inset-0 bg-black/60 flex justify-center items-center z-50 p-4 backdrop-blur-md animate-fadeIn">
<div className="bg-white text-banquise-blue-dark rounded-3xl max-w-4xl w-full max-h-[90vh] shadow-2xl relative animate-slideUp border border-banquise-blue-lightest/20 overflow-hidden">
<div className="flex flex-col lg:flex-row items-center lg:items-start mb-4"> {/* Bouton de fermeture fixe au-dessus du contenu */}
<div className="w-16 h-16 sm:w-20 sm:h-20 lg:w-24 lg:h-24 bg-white/20 rounded-3xl flex items-center justify-center text-3xl sm:text-4xl lg:text-5xl mb-4 lg:mb-0 lg:mr-8 backdrop-blur-sm"> <div className="absolute top-4 right-4 z-50">
{service.icon} <button
</div> onClick={onClose}
<div className="text-center lg:text-left flex-1"> className="bg-white/90 hover:bg-white border border-banquise-blue/20 text-xl cursor-pointer text-banquise-blue-dark flex items-center justify-center w-10 h-10 sm:w-12 sm:h-12 rounded-full transition-all duration-200 hover:scale-110 active:scale-95 shadow-lg backdrop-blur-sm"
<h2 className="font-heading text-2xl sm:text-3xl lg:text-5xl mt-0 mb-3 lg:mb-4 leading-tight"> aria-label="Fermer la popup"
{service.name}
</h2>
<div className="text-white/90 text-base sm:text-lg lg:text-xl font-medium">
Service d'hébergement professionnel
</div>
<div className="mt-4 lg:mt-6 flex flex-wrap gap-2">
<span className="bg-white/20 text-white px-3 py-1 rounded-full text-sm font-medium backdrop-blur-sm">Haute disponibilité</span>
<span className="bg-white/20 text-white px-3 py-1 rounded-full text-sm font-medium backdrop-blur-sm">Open Source</span>
<span className="bg-white/20 text-white px-3 py-1 rounded-full text-sm font-medium backdrop-blur-sm">Communautaire</span>
</div>
</div>
</div>
</div>
{/* Content - Layout simplifié */}
<div className="p-6 sm:p-8">
{/* Description */}
<h3 className="text-lg sm:text-xl lg:text-2xl font-bold text-banquise-blue-dark mb-4 lg:mb-6 font-heading flex items-center">
<span className="text-xl sm:text-2xl lg:text-3xl mr-3">📋</span>
Description détaillée
</h3>
<div className="bg-gradient-to-br from-banquise-blue/5 to-banquise-blue-light/5 rounded-2xl p-4 lg:p-6 border border-banquise-blue/10 mb-8">
<p className="text-banquise-blue-dark/80 leading-relaxed text-base sm:text-lg lg:text-xl mb-4">
{service.description}
</p>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-6">
<div className="flex items-center p-3 bg-white/60 rounded-xl border border-banquise-blue/10">
<div className="w-10 h-10 bg-gradient-to-br from-green-500 to-green-600 rounded-lg flex items-center justify-center text-white mr-3">
</div>
<div>
<div className="font-semibold text-banquise-blue-dark text-sm">99.9% Uptime</div>
<div className="text-banquise-blue-dark/70 text-xs">Disponibilité garantie</div>
</div>
</div>
<div className="flex items-center p-3 bg-white/60 rounded-xl border border-banquise-blue/10">
<div className="w-10 h-10 bg-gradient-to-br from-blue-500 to-blue-600 rounded-lg flex items-center justify-center text-white mr-3">
🔒
</div>
<div>
<div className="font-semibold text-banquise-blue-dark text-sm">Sécurisé</div>
<div className="text-banquise-blue-dark/70 text-xs">SSL & Backups</div>
</div>
</div>
</div>
</div>
{/* Fonctionnalités en colonnes */}
<h3 className="text-lg sm:text-xl lg:text-2xl font-bold text-banquise-blue-dark mb-4 lg:mb-6 font-heading flex items-center">
<span className="text-xl sm:text-2xl lg:text-3xl mr-3"></span>
Fonctionnalités principales
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-8">
{service.features.map((feature, index) => (
<div key={index} className="flex items-start bg-banquise-blue/5 rounded-xl p-4 border border-banquise-blue/10 hover:bg-banquise-blue/10 transition-colors duration-200 group">
<div className="w-6 h-6 bg-gradient-to-br from-banquise-blue to-banquise-blue-light rounded-full flex items-center justify-center mr-3 mt-0.5 flex-shrink-0 group-hover:scale-110 transition-transform duration-200">
<div className="w-2 h-2 bg-white rounded-full"></div>
</div>
<span className="text-banquise-blue-dark/90 font-medium text-sm lg:text-base leading-relaxed">{feature}</span>
</div>
))}
</div>
{/* Call to action simplifié */}
<div className="pt-6 lg:pt-8 border-t border-banquise-blue/10">
<a
href={service.url}
target="_blank"
rel="noopener noreferrer"
className="w-full inline-flex items-center justify-center bg-gradient-to-r from-banquise-blue to-banquise-blue-light text-white border-0 py-4 px-6 sm:px-8 rounded-2xl cursor-pointer no-underline font-bold tracking-wide shadow-lg transition-all duration-300 hover:shadow-xl hover:-translate-y-1 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-banquise-blue-light text-base lg:text-lg hover:scale-[1.02] active:scale-95"
> >
<span className="mr-3 text-xl lg:text-2xl">🚀</span> ×
<span>Accéder à {service.name}</span> </button>
</a>
<p className="text-center text-sm text-banquise-blue-dark/60 mt-4">
Besoin d'aide ? Rejoignez notre <a href="https://discord.gg/labanquise" className="text-banquise-blue hover:text-banquise-blue-dark transition-colors duration-200 font-medium">Discord</a> pour obtenir du support
</p>
</div> </div>
</div>
{/* Contenu avec scroll vertical uniquement */}
<div className="overflow-y-auto overflow-x-hidden max-h-[90vh] popup-content">
{/* Header */}
<div className="relative bg-gradient-to-r from-banquise-blue to-banquise-blue-light p-6 sm:p-8 text-white pr-16 sm:pr-20">
<div className="flex flex-col lg:flex-row items-center lg:items-start mb-4">
<div className="w-16 h-16 sm:w-20 sm:h-20 lg:w-24 lg:h-24 bg-white/20 rounded-3xl flex items-center justify-center text-3xl sm:text-4xl lg:text-5xl mb-4 lg:mb-0 lg:mr-8 backdrop-blur-sm">
{service.icon}
</div>
<div className="text-center lg:text-left flex-1">
<h2 className="font-heading text-2xl sm:text-3xl lg:text-4xl mt-0 mb-3 lg:mb-4 leading-tight font-bold text-white">
{service.name}
</h2>
<div className="text-white/90 text-base sm:text-lg lg:text-xl font-medium">
Service d'hébergement professionnel
</div>
<div className="mt-4 lg:mt-6 flex flex-wrap gap-2 justify-center lg:justify-start">
<span className="bg-white/20 text-white px-3 py-1 rounded-full text-sm font-medium backdrop-blur-sm">Haute disponibilité</span>
<span className="bg-white/20 text-white px-3 py-1 rounded-full text-sm font-medium backdrop-blur-sm">Open Source</span>
<span className="bg-white/20 text-white px-3 py-1 rounded-full text-sm font-medium backdrop-blur-sm">Communautaire</span>
</div>
</div>
</div>
</div>
{/* Decorative elements - améliorés pour desktop */} {/* Content - Forcer le fond blanc */}
<div className="absolute top-0 right-0 w-24 h-24 lg:w-40 lg:h-40 bg-banquise-blue-lightest/10 rounded-full -translate-y-12 translate-x-12 lg:-translate-y-20 lg:translate-x-20 hidden sm:block"></div> <div className="p-6 sm:p-8 bg-white">
<div className="absolute bottom-0 left-0 w-16 h-16 lg:w-32 lg:h-32 bg-banquise-blue/5 rounded-full translate-y-8 -translate-x-8 lg:translate-y-16 lg:-translate-x-16 hidden sm:block"></div> {/* Description */}
<div className="absolute top-1/2 left-0 w-20 h-20 lg:w-28 lg:h-28 bg-banquise-blue-light/5 rounded-full -translate-x-10 lg:-translate-x-14 hidden lg:block"></div> <h3 className="text-xl sm:text-2xl lg:text-3xl mb-4 lg:mb-6 text-banquise-blue-dark font-heading font-bold flex items-center">
<span className="text-xl sm:text-2xl lg:text-3xl mr-3">📋</span>
Description détaillée
</h3>
<div className="bg-gradient-to-br from-banquise-blue/5 to-banquise-blue-light/5 rounded-2xl p-4 lg:p-6 border border-banquise-blue/10 mb-8">
<p className="text-banquise-blue-dark/90 leading-relaxed text-base sm:text-lg lg:text-xl mb-4">
{service.description}
</p>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-6">
<div className="flex items-center p-3 bg-white/60 rounded-xl border border-banquise-blue/10">
<div className="w-10 h-10 bg-gradient-to-br from-banquise-blue to-banquise-blue-light rounded-lg flex items-center justify-center text-white mr-3">
</div>
<div>
<div className="font-semibold text-banquise-blue-dark text-sm">99.9% Uptime</div>
<div className="text-banquise-blue-dark/70 text-xs">Disponibilité garantie</div>
</div>
</div>
<div className="flex items-center p-3 bg-white/60 rounded-xl border border-banquise-blue/10">
<div className="w-10 h-10 bg-gradient-to-br from-blue-500 to-blue-600 rounded-lg flex items-center justify-center text-white mr-3">
🔒
</div>
<div>
<div className="font-semibold text-banquise-blue-dark text-sm">Sécurisé</div>
<div className="text-banquise-blue-dark/70 text-xs">SSL & Backups</div>
</div>
</div>
</div>
</div>
{/* Fonctionnalités */}
<h3 className="text-xl sm:text-2xl lg:text-3xl mb-4 lg:mb-6 text-banquise-blue-dark font-heading font-bold flex items-center">
<span className="text-xl sm:text-2xl lg:text-3xl mr-3"></span>
Fonctionnalités principales
</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-8">
{service.features.map((feature, index) => (
<div key={index} className="flex items-start bg-banquise-blue/5 rounded-xl p-4 border border-banquise-blue/10 hover:bg-banquise-blue/10 transition-colors duration-200 group">
<div className="w-6 h-6 bg-gradient-to-br from-banquise-blue to-banquise-blue-light rounded-full flex items-center justify-center mr-3 mt-0.5 flex-shrink-0 group-hover:scale-110 transition-transform duration-200">
<div className="w-2 h-2 bg-white rounded-full"></div>
</div>
<span className="text-banquise-blue-dark/90 font-medium text-sm lg:text-base leading-relaxed">{feature}</span>
</div>
))}
</div>
{/* Call to action */}
<div className="pt-6 lg:pt-8 border-t border-banquise-blue/10">
<a
href={service.url}
target="_blank"
rel="noopener noreferrer"
className="w-full inline-flex items-center justify-center bg-gradient-to-r from-banquise-blue to-banquise-blue-light text-white border-0 py-4 px-6 sm:px-8 rounded-2xl cursor-pointer no-underline font-bold tracking-wide shadow-lg transition-all duration-300 hover:shadow-xl hover:-translate-y-1 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-banquise-blue-light text-base lg:text-lg hover:scale-[1.02] active:scale-95"
>
<span className="mr-3 text-xl lg:text-2xl">🚀</span>
<span>Accéder à {service.name}</span>
</a>
<p className="text-center text-sm text-banquise-blue-dark/60 mt-4">
Besoin d'aide ? Rejoignez notre <a href={URLS.social.discord} className="text-banquise-blue hover:text-banquise-blue-dark transition-colors duration-200 font-medium">Discord</a> pour obtenir du support
</p>
</div>
</div>
</div>
{/* Decorative elements */}
<div className="absolute top-0 right-0 w-16 h-16 sm:w-24 sm:h-24 lg:w-32 lg:h-32 bg-banquise-blue-lightest/10 rounded-full -translate-y-8 translate-x-8 sm:-translate-y-12 sm:translate-x-12 lg:-translate-y-16 lg:translate-x-16 hidden sm:block pointer-events-none"></div>
<div className="absolute bottom-0 left-0 w-12 h-12 sm:w-16 sm:h-16 lg:w-24 lg:h-24 bg-banquise-blue/5 rounded-full translate-y-6 -translate-x-6 sm:translate-y-8 sm:-translate-x-8 lg:translate-y-12 lg:-translate-x-12 hidden sm:block pointer-events-none"></div>
</div>
</div> </div>
</div> );
); };

View File

@ -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 (
<button
onClick={scrollToTop}
className={`fixed bottom-6 right-6 z-50 w-12 h-12 sm:w-14 sm:h-14 bg-gradient-to-r from-banquise-blue to-banquise-blue-light text-white rounded-full shadow-lg hover:shadow-xl transition-all duration-300 flex items-center justify-center group border border-banquise-blue-lightest/30 backdrop-blur-sm ${
isVisible
? 'opacity-100 translate-y-0 scale-100'
: 'opacity-0 translate-y-4 scale-95 pointer-events-none'
}`}
aria-label="Retour en haut de page"
>
<svg
className="w-5 h-5 sm:w-6 sm:h-6 transition-transform duration-300 group-hover:-translate-y-0.5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2.5}
d="M7 11l5-5m0 0l5 5m-5-5v12"
/>
</svg>
{/* Effet de lueur au hover */}
<div className="absolute inset-0 bg-gradient-to-r from-banquise-blue-light to-banquise-blue rounded-full opacity-0 group-hover:opacity-75 transition-opacity duration-300 blur-sm"></div>
</button>
);
};

View File

@ -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;

View File

@ -50,6 +50,64 @@
50% { transform: translateY(-30px) rotate(-2deg); } 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 */ /* Apply animations */
.animate-parallax-slow { .animate-parallax-slow {
animation: parallax-slow 20s ease-in-out infinite; animation: parallax-slow 20s ease-in-out infinite;
@ -82,3 +140,46 @@
.animate-float-very-slow { .animate-float-very-slow {
animation: float-very-slow 12s ease-in-out infinite; animation: float-very-slow 12s ease-in-out infinite;
} }
/* Amélioration du scroll */
html {
scroll-behavior: smooth;
}
/* Empêcher le scroll horizontal global */
body {
overflow-x: hidden;
}
/* Styles pour les popups */
.popup-content {
scrollbar-width: thin;
scrollbar-color: rgba(31, 93, 137, 0.3) transparent;
}
.popup-content::-webkit-scrollbar {
width: 6px;
}
.popup-content::-webkit-scrollbar-track {
background: transparent;
}
.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;
}

View File

@ -3,6 +3,18 @@ import { createRoot } from 'react-dom/client'
import './index.css' import './index.css'
import App from './App.tsx' 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( createRoot(document.getElementById('root')!).render(
<StrictMode> <StrictMode>
<App /> <App />

View File

@ -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;

View File

@ -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;
}