diff --git a/banquise-website/index.html b/banquise-website/index.html index ee5ab91..2ac6584 100644 --- a/banquise-website/index.html +++ b/banquise-website/index.html @@ -10,7 +10,7 @@ - +
diff --git a/banquise-website/src/App.css b/banquise-website/src/App.css index febed48..b797a0b 100644 --- a/banquise-website/src/App.css +++ b/banquise-website/src/App.css @@ -1,1434 +1 @@ -#root { - max-width: 100%; - margin: 0; - padding: 0; - text-align: center; - width: 100%; -} - -.app-container { - display: flex; - flex-direction: column; - min-height: 100vh; - width: 100%; -} - -/* ===== NAVIGATION ===== */ -.navbar { - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.8rem 2rem; - background-color: rgba(31, 93, 137, 0.95); - color: white; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - width: 100%; - box-sizing: border-box; - z-index: 10; - backdrop-filter: blur(8px); - border-bottom: 1px solid rgba(255, 255, 255, 0.1); - position: sticky; - top: 0; -} - -.navbar-left { - display: flex; - align-items: center; -} - -.site-logo { - height: 2.2rem; - width: auto; - margin-right: 1rem; - filter: drop-shadow(0 0 5px rgba(168, 218, 255, 0.4)); -} - -.site-name { - font-size: 1.6rem; - font-weight: 700; - margin: 0; - color: #ffffff; - letter-spacing: 0.5px; - font-family: var(--font-heading); -} - -.navbar-right { - display: flex; - align-items: center; - gap: 12px; -} - -.discord-button { - display: flex; - align-items: center; - background-color: #40B4FF; - color: white; - border: none; - padding: 0.6rem 1.2rem; - border-radius: 6px; - cursor: pointer; - text-decoration: none; - font-weight: 600; - letter-spacing: 0.3px; - box-shadow: 0 2px 8px rgba(64, 180, 255, 0.4); - transition: all 0.2s ease; -} - -.discord-button:hover { - background-color: #2ba3f7; - color: #ffffff; - text-shadow: 0 0 1px rgba(255, 255, 255, 0.5); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(64, 180, 255, 0.6); -} - -.discord-button:focus-visible { - outline: 3px solid #ffffff; - outline-offset: 2px; - background-color: #2ba3f7; -} - -.login-button { - display: flex; - align-items: center; - background-color: rgba(105, 183, 226, 0.9); - color: white; - border: none; - padding: 0.6rem 1.2rem; - border-radius: 6px; - cursor: pointer; - text-decoration: none; - font-weight: 600; - letter-spacing: 0.3px; - box-shadow: 0 2px 8px rgba(105, 183, 226, 0.3); - transition: all 0.2s ease; -} - -.login-button:hover { - background-color: #69B7E2; - color: #ffffff; - text-shadow: 0 0 1px rgba(255, 255, 255, 0.5); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(105, 183, 226, 0.5); -} - -.login-button:focus-visible { - outline: 3px solid #ffffff; - outline-offset: 2px; - background-color: #69B7E2; -} - -.login-icon { - margin-right: 0.5rem; -} - -.navbar-mobile-toggle { - display: none; - background: transparent; - border: none; - cursor: pointer; - padding: 5px; - z-index: 20; - width: 40px; - height: 40px; - position: relative; -} - -.navbar-mobile-toggle span { - display: block; - width: 25px; - height: 3px; - background-color: white; - margin: 5px auto; - transition: all 0.3s ease; -} - -.mobile-menu-overlay { - display: none; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.5); - z-index: 14; - visibility: hidden; - opacity: 0; - transition: opacity 0.3s ease, visibility 0.3s ease; -} - -.mobile-menu-overlay.active { - display: block; - visibility: visible; - opacity: 1; -} - -/* ===== MAIN CONTENT ===== */ -.content { - flex: 1; - display: flex; - flex-direction: column; - overflow-x: hidden; - overflow-y: auto; -} - -.ocean { - position: relative; - flex: 1; - background: linear-gradient(180deg, #40B4FF 0%, #69B7E2 50%, #1F5D89 100%); - width: 100%; - min-height: calc(100vh - 72px); - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: center; - overflow-x: hidden; -} - -.page-section { - width: 100%; - max-width: 1200px; - margin: 2rem auto; - padding: 2rem; - position: relative; - z-index: 3; - display: flex; - flex-direction: column; - align-items: center; - box-sizing: border-box; -} - -/* ===== HERO SECTION ===== */ -.hero-section { - min-height: calc(70vh - 72px); - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - text-align: center; - padding-top: 3rem; - padding-bottom: 3rem; - margin-top: 0; -} - -.hero-title { - color: #F6F6F6; - font-size: 3.5rem; - margin-bottom: 1.5rem; - font-weight: 800; - text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); - line-height: 1.1; - max-width: 800px; -} - -.hero-subtitle { - color: #F6F6F6; - font-size: 1.5rem; - margin-bottom: 2.5rem; - max-width: 700px; - font-weight: 400; - opacity: 0.9; - text-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); -} - -.hero-logo-container { - margin-bottom: 2rem; - width: 150px; - height: 150px; - border-radius: 50%; - background: rgba(255, 255, 255, 0.1); - padding: 1rem; - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); - animation: gentle-float 6s ease-in-out infinite; -} - -.hero-logo { - width: 100%; - height: 100%; - object-fit: contain; - filter: drop-shadow(0 5px 15px rgba(0, 0, 0, 0.2)); -} - -.hero-tech-elements { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - pointer-events: none; - z-index: 1; -} - -.tech-element { - position: absolute; - font-size: 2.5rem; - color: rgba(255, 255, 255, 0.15); - animation: tech-float 10s ease-in-out infinite; -} - -.tech-element-1 { - top: 15%; - left: 10%; - animation-delay: 0s; -} - -.tech-element-2 { - top: 25%; - right: 15%; - animation-delay: 2s; -} - -.tech-element-3 { - bottom: 20%; - left: 15%; - animation-delay: 1s; -} - -.tech-element-4 { - bottom: 30%; - right: 10%; - animation-delay: 3s; -} - -@keyframes tech-float { - 0%, 100% { transform: translateY(0) rotate(0deg); opacity: 0.15; } - 50% { transform: translateY(-20px) rotate(10deg); opacity: 0.25; } -} - -.cta-button { - display: inline-flex; - align-items: center; - justify-content: center; - background-color: #F6F6F6; - color: #1F5D89; - border: none; - padding: 1rem 2.5rem; - border-radius: 30px; - font-size: 1.1rem; - font-weight: 600; - text-decoration: none; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15); - transition: all 0.3s ease; - min-width: 200px; -} - -.cta-button:hover { - transform: translateY(-3px); - box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2); - background-color: #ffffff; -} - -.cta-icon { - margin-left: 0.75rem; - transition: transform 0.2s ease; -} - -.cta-button:hover .cta-icon { - transform: translateX(3px); -} - -/* ===== SECTION STYLING ===== */ -.section-divider { - width: 80px; - height: 4px; - background: linear-gradient(90deg, #A5F0FF, #40B4FF); - margin: 0 auto 2rem; - border-radius: 2px; -} - -.section-title { - color: #F6F6F6; - text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); - font-size: 2.5rem; - margin-bottom: 1rem; - text-align: center; - font-family: var(--font-heading); - font-weight: 700; - letter-spacing: -0.01em; -} - -.section-subtitle { - color: #F6F6F6; - text-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); - font-size: 1.25rem; - opacity: 0.9; - margin-bottom: 3.5rem; - max-width: 800px; - text-align: center; -} - -/* ===== TECH FEATURES SECTION ===== */ -.tech-features-section { - padding-top: 3rem; - padding-bottom: 4rem; - position: relative; - z-index: 2; -} - -.tech-features-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 2rem; - width: 100%; -} - -.tech-feature-card { - background: rgba(31, 93, 137, 0.1); - border-radius: 12px; - padding: 2rem; - display: flex; - flex-direction: column; - align-items: center; - text-align: center; - transition: transform 0.3s ease, background-color 0.3s ease; - border: 1px solid rgba(255, 255, 255, 0.05); -} - -.tech-feature-card:hover { - transform: translateY(-5px); - background: rgba(31, 93, 137, 0.2); -} - -.tech-feature-icon { - font-size: 2.5rem; - margin-bottom: 1.5rem; - color: #A5F0FF; - background: rgba(31, 93, 137, 0.3); - width: 70px; - height: 70px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 50%; - box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); -} - -.tech-feature-title { - font-size: 1.3rem; - margin-bottom: 1rem; - color: #F6F6F6; - font-family: var(--font-heading); - font-weight: 600; -} - -.tech-feature-description { - color: rgba(246, 246, 246, 0.85); - line-height: 1.6; - font-size: 1rem; -} - -/* ===== SERVICES SECTION ===== */ -.services-section { - position: relative; - z-index: 2; - padding-top: 3rem; - padding-bottom: 5rem; - margin-top: 0; - margin-bottom: 0; -} - -.icebergs-container { - position: relative; - width: 100%; - max-width: 1000px; - height: auto; - min-height: 350px; - z-index: 2; - display: flex; - justify-content: center; - align-items: center; - margin: 3rem auto; - padding: 0; - gap: 5%; - flex-wrap: wrap; -} - -.iceberg { - position: relative; - cursor: pointer; - text-decoration: none; - width: 250px; - height: 200px; - display: flex; - align-items: center; - justify-content: center; - transition: transform 0.3s ease; - z-index: 3; - margin: 1.5rem; -} - -.iceberg:hover { - transform: translateY(-10px) !important; -} - -.iceberg img { - width: 100%; - height: auto; - max-width: 250px; - max-height: 200px; - object-fit: contain; - filter: drop-shadow(0 10px 15px rgba(0, 0, 0, 0.3)); -} - -.service-name { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - color: #1F5D89; - font-weight: 700; - font-size: 1.4rem; - background-color: rgba(255, 255, 255, 0.92); - padding: 12px 20px; - border-radius: 10px; - text-align: center; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15), 0 0 0 2px rgba(165, 240, 255, 0.5); - z-index: 4; - font-family: var(--font-heading); - letter-spacing: -0.01em; - border: 1px solid rgba(165, 240, 255, 0.8); - backdrop-filter: blur(4px); - transition: all 0.3s ease; - min-width: 160px; - max-width: 90%; - width: auto; -} - -.iceberg:hover .service-name { - background-color: rgba(255, 255, 255, 0.97); - box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2), 0 0 0 3px rgba(165, 240, 255, 0.7); - transform: translate(-50%, -55%); - color: #40B4FF; -} - -.float-1 { - animation: float1 5s ease-in-out infinite; -} - -.float-2 { - animation: float2 6s ease-in-out infinite; -} - -.float-3 { - animation: float3 7s ease-in-out infinite; -} - -@keyframes float1 { - 0%, 100% { transform: translateY(0); } - 50% { transform: translateY(-15px); } -} - -@keyframes float2 { - 0%, 100% { transform: translateY(0); } - 50% { transform: translateY(-20px); } -} - -@keyframes float3 { - 0%, 100% { transform: translateY(0); } - 50% { transform: translateY(-10px); } -} - -/* ===== ABOUT SECTION ===== */ -.about-section { - position: relative; - background-color: rgba(31, 93, 137, 0.15); - backdrop-filter: blur(10px); - margin: 0; - padding: 4rem 2rem; - z-index: 2; - border-top: 1px solid rgba(255, 255, 255, 0.1); - border-bottom: 1px solid rgba(255, 255, 255, 0.1); - width: 100%; - box-sizing: border-box; -} - -.about-container { - max-width: 1000px; - margin: 0 auto; - display: flex; - flex-direction: column; - align-items: center; - width: 100%; -} - -.about-image-container { - max-width: 180px; - margin: 0 auto 2rem; - position: relative; - z-index: 2; -} - -.about-logo { - width: 100%; - height: auto; - border-radius: 50%; - padding: 1rem; - background: rgba(255, 255, 255, 0.05); - border: 2px solid rgba(165, 240, 255, 0.3); - box-shadow: 0 10px 25px rgba(31, 93, 137, 0.3); - animation: gentle-float 6s ease-in-out infinite; -} - -@keyframes gentle-float { - 0%, 100% { - transform: translateY(0); - } - 50% { - transform: translateY(-10px); - } -} - -.about-intro { - text-align: center; - max-width: 800px; - margin: 0 auto 2.5rem; - color: #F6F6F6; - font-size: 1.1rem; - line-height: 1.6; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); -} - -.about-text { - flex: 1; - min-width: 300px; - max-width: 600px; - color: white; - text-align: left; -} - -.about-text h3 { - font-size: 2rem; - margin-bottom: 1.5rem; - color: white; - text-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); -} - -.about-text p { - margin-bottom: 1.25rem; - line-height: 1.7; - font-size: 1.1rem; -} - -.about-image { - flex: 1; - min-width: 300px; - max-width: 500px; - display: flex; - justify-content: center; - align-items: center; -} - -.about-image img { - width: 100%; - height: auto; - border-radius: 12px; - box-shadow: 0 15px 30px rgba(0, 0, 0, 0.25); - transform: perspective(1000px) rotateY(-5deg); - transition: transform 0.5s ease; -} - -.about-image img:hover { - transform: perspective(1000px) rotateY(0); -} - -/* ===== ACCORDION STYLES ===== */ -.accordion-group { - width: 100%; - display: flex; - flex-direction: column; - gap: 1rem; - margin-top: 1.5rem; -} - -.accordion-item { - background: rgba(31, 93, 137, 0.1); - border-radius: 12px; - overflow: hidden; - border: 1px solid rgba(165, 240, 255, 0.2); - transition: all 0.3s ease; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05); -} - -.accordion-item:hover { - background: rgba(31, 93, 137, 0.2); - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1); -} - -.accordion-header { - padding: 1.2rem 1.5rem; - cursor: pointer; - display: flex; - align-items: center; - justify-content: space-between; - font-weight: 600; - color: #F6F6F6; - background: rgba(31, 93, 137, 0.2); - transition: all 0.2s ease; - font-size: 1.1rem; - user-select: none; -} - -.accordion-header:hover { - background: rgba(64, 180, 255, 0.2); -} - -.accordion-toggle-icon { - font-size: 1.2rem; - transition: transform 0.3s ease; - color: #A5F0FF; -} - -.accordion-item.active .accordion-toggle-icon { - transform: rotate(180deg); -} - -.accordion-content { - max-height: 0; - overflow: hidden; - transition: max-height 0.5s cubic-bezier(0, 1, 0, 1), padding 0.3s ease; - background: rgba(31, 93, 137, 0.05); - line-height: 1.6; - font-size: 1rem; - color: rgba(246, 246, 246, 0.9); -} - -.accordion-item.active .accordion-content { - max-height: 1000px; - transition: max-height 1s ease-in-out, padding 0.3s ease; - padding: 1.5rem; -} - -.accordion-content p { - margin-top: 0; -} - -.accordion-content p:last-child { - margin-bottom: 0; -} - -.accordion-content ul, .accordion-content ol { - margin-top: 0.5rem; - margin-bottom: 0.5rem; - padding-left: 1.5rem; -} - -.accordion-content li { - margin-bottom: 0.5rem; -} - -.accordion-cta { - display: inline-flex; - align-items: center; - background-color: #40B4FF; - color: white; - border: none; - padding: 0.7rem 1.2rem; - border-radius: 6px; - margin-top: 1rem; - text-decoration: none; - font-weight: 600; - transition: all 0.2s ease; -} - -.accordion-cta:hover { - background-color: #2ba3f7; - transform: translateY(-2px); - box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15); -} - -.accordion-cta-icon { - margin-left: 0.5rem; - font-size: 0.9rem; -} - -/* ===== STATISTICS SECTION ===== */ -.stats-section { - background: linear-gradient(180deg, rgba(64, 180, 255, 0.2) 0%, rgba(31, 93, 137, 0) 100%); - padding: 4rem 2rem; - position: relative; - z-index: 2; -} - -.stats-container { - max-width: 1200px; - margin: 0 auto; - display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 2rem; -} - -.stat-card { - background: rgba(31, 93, 137, 0.1); - border-radius: 12px; - padding: 2rem; - text-align: center; - transition: transform 0.3s ease, background-color 0.3s ease; - border: 1px solid rgba(255, 255, 255, 0.05); -} - -.stat-card:hover { - transform: translateY(-5px); - background: rgba(31, 93, 137, 0.15); -} - -.stat-icon { - font-size: 2.5rem; - margin-bottom: 1rem; - color: #40B4FF; -} - -.stat-title { - font-size: 1.2rem; - margin-bottom: 0.5rem; - color: #F6F6F6; -} - -.stat-value { - font-size: 2rem; - font-weight: 700; - color: #A5F0FF; -} - -/* ===== FEATURES SECTION ===== */ -.features-section { - background: linear-gradient(180deg, rgba(64, 180, 255, 0.2) 0%, rgba(31, 93, 137, 0) 100%); - padding: 4rem 2rem; - position: relative; - z-index: 2; -} - -.feature-card { - background: rgba(31, 93, 137, 0.1); - border-radius: 12px; - padding: 2rem; - transition: transform 0.3s ease, background-color 0.3s ease; -} - -.feature-card:hover { - transform: translateY(-5px); - background: rgba(64, 180, 255, 0.15); -} - -.feature-icon { - font-size: 2rem; - margin-bottom: 1rem; - color: #A5F0FF; - background: rgba(31, 93, 137, 0.3); - padding: 1rem; - border-radius: 50%; -} - -.feature-title { - font-size: 1.2rem; - margin-bottom: 0.5rem; - color: #F6F6F6; -} - -.feature-description { - color: #F6F6F6; - line-height: 1.6; -} - -/* ===== FAQ SECTION ===== */ -.faq-section { - background: rgba(31, 93, 137, 0.05); - padding: 4rem 2rem; - position: relative; - z-index: 2; -} - -.faq-item { - background: rgba(31, 93, 137, 0.08); - border-radius: 8px; - margin-bottom: 1.5rem; - padding: 1.5rem; - transition: background 0.3s ease; -} - -.faq-item:hover { - background: rgba(31, 93, 137, 0.12); -} - -.faq-question { - font-size: 1.1rem; - margin-bottom: 0.5rem; - color: #F6F6F6; -} - -.faq-answer { - color: #F6F6F6; - line-height: 1.6; -} - -/* ===== CODE BACKGROUND ===== */ -.code-background { - position: absolute; - bottom: 5%; - right: 5%; - text-align: left; - color: rgba(255, 255, 255, 0.1); - font-family: 'Courier New', monospace; - font-size: 0.9rem; - line-height: 1.6; - pointer-events: none; - z-index: 1; -} - -.code-line { - white-space: nowrap; -} - -/* ===== WAVES EFFECT ===== */ -.waves { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 200px; - overflow: hidden; - z-index: 1; - pointer-events: none; -} - -.wave { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 100px; - background: url('data:image/svg+xml,') repeat-x; - background-size: 1200px 100px; - animation: wave 10s linear infinite; -} - -.wave1 { - opacity: 0.3; - animation: wave 20s linear infinite; - z-index: 1; -} - -.wave2 { - opacity: 0.5; - animation-delay: -5s; - animation: waveReverse 15s linear infinite; - bottom: -10px; - z-index: 2; -} - -.wave3 { - opacity: 0.7; - animation-delay: -2s; - animation: wave 12s linear infinite; - bottom: -20px; - z-index: 3; -} - -@keyframes wave { - 0% { background-position: 0; } - 100% { background-position: 1200px; } -} - -@keyframes waveReverse { - 0% { background-position: 1200px; } - 100% { background-position: 0; } -} - -/* ===== POPUP STYLES ===== */ -.popup-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.7); - display: flex; - justify-content: center; - align-items: center; - z-index: 100; - padding: 1rem; - backdrop-filter: blur(3px); - animation: fadeIn 0.2s ease-out; -} - -.popup-content { - background: linear-gradient(135deg, #F6F6F6 0%, #E8F7FF 100%); - color: #1F5D89; - border-radius: 12px; - padding: 2rem; - max-width: 500px; - width: 100%; - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); - position: relative; - overflow: hidden; - animation: slideUp 0.3s ease-out; -} - -.popup-close { - position: absolute; - top: 15px; - right: 15px; - background: none; - border: none; - font-size: 1.5rem; - cursor: pointer; - color: #1F5D89; - display: flex; - align-items: center; - justify-content: center; - width: 32px; - height: 32px; - border-radius: 50%; - transition: background-color 0.2s; - padding: 0; -} - -.popup-close:hover { - background-color: rgba(64, 180, 255, 0.1); -} - -.popup-title { - font-family: var(--font-heading); - font-size: 1.8rem; - margin-top: 0; - margin-bottom: 1rem; - color: #1F5D89; - line-height: 1.2; -} - -.popup-description { - font-size: 1.1rem; - line-height: 1.5; - margin-bottom: 1.5rem; - color: #1F5D89; -} - -.popup-button { - display: inline-flex; - align-items: center; - background-color: #40B4FF; - color: white; - border: none; - padding: 0.8rem 1.5rem; - border-radius: 6px; - cursor: pointer; - text-decoration: none; - font-weight: 600; - letter-spacing: 0.3px; - box-shadow: 0 2px 8px rgba(64, 180, 255, 0.3); - transition: all 0.2s ease; -} - -.popup-button:hover { - background-color: #2ba3f7; - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(64, 180, 255, 0.4); -} - -.popup-button:focus-visible { - outline: 3px solid #69B7E2; - outline-offset: 2px; -} - -.popup-button-icon { - margin-right: 0.5rem; - font-size: 1.1em; -} - -@keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -@keyframes slideUp { - from { - transform: translateY(30px); - opacity: 0; - } - to { - transform: translateY(0); - opacity: 1; - } -} - -/* ===== BUBBLES EFFECT ===== */ -.bubbles { - position: absolute; - width: 100%; - height: 100%; - overflow: hidden; - top: 0; - left: 0; - z-index: 1; - pointer-events: none; -} - -.bubble { - position: absolute; - bottom: -20px; - width: 40px; - height: 40px; - background: rgba(165, 240, 255, 0.2); - border-radius: 50%; - opacity: 0.8; - animation: rise 10s infinite ease-in; -} - -.bubble:nth-child(1) { - width: 25px; - height: 25px; - left: 10%; - animation-duration: 8s; -} - -.bubble:nth-child(2) { - width: 30px; - height: 30px; - left: 20%; - animation-duration: 9s; - animation-delay: 1s; -} - -.bubble:nth-child(3) { - width: 35px; - height: 35px; - left: 35%; - animation-duration: 10s; - animation-delay: 2s; -} - -.bubble:nth-child(4) { - width: 28px; - height: 28px; - left: 50%; - animation-duration: 7s; - animation-delay: 0s; -} - -.bubble:nth-child(5) { - width: 22px; - height: 22px; - left: 65%; - animation-duration: 12s; - animation-delay: 3s; -} - -.bubble:nth-child(6) { - width: 32px; - height: 32px; - left: 80%; - animation-duration: 9s; - animation-delay: 1.5s; -} - -.bubble:nth-child(7) { - width: 20px; - height: 20px; - left: 90%; - animation-duration: 8s; - animation-delay: 2.5s; -} - -@keyframes 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; - } -} - -/* ===== FOOTER ===== */ -.footer { - background-color: #1F5D89; - color: white; - padding: 4rem 2rem 2rem; - position: relative; - z-index: 3; - border-top: 1px solid rgba(255, 255, 255, 0.1); - width: 100%; - box-sizing: border-box; -} - -.footer-content { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - max-width: 1200px; - margin: 0 auto; -} - -.footer-column { - flex: 1; - min-width: 250px; - margin-bottom: 2rem; - text-align: left; - padding: 0 1.5rem; -} - -.footer-column h4 { - font-size: 1.2rem; - margin-bottom: 1.5rem; - color: #A5F0FF; - position: relative; - padding-bottom: 0.75rem; -} - -.footer-column h4:after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - width: 40px; - height: 2px; - background-color: #A5F0FF; -} - -.footer-column ul { - list-style: none; - padding: 0; - margin: 0; -} - -.footer-column ul li { - margin-bottom: 0.8rem; -} - -.footer-column a { - color: rgba(246, 246, 246, 0.8); - text-decoration: none; - transition: all 0.2s; - display: inline-flex; - align-items: center; -} - -.footer-column a:hover { - color: #F6F6F6; - transform: translateX(3px); -} - -.footer-bottom { - border-top: 1px solid rgba(255, 255, 255, 0.1); - padding-top: 1.5rem; - margin-top: 2rem; - text-align: center; - font-size: 0.9rem; - color: rgba(255, 255, 255, 0.7); - max-width: 1200px; - margin-left: auto; - margin-right: auto; -} - -/* ===== ACCESSIBILITY ===== */ -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border-width: 0; -} - -.sr-only.focus:not-sr-only { - position: fixed; - top: 0; - left: 0; - background: #1F5D89; - color: white; - padding: 0.5rem 1rem; - z-index: 999; - width: auto; - height: auto; - clip: auto; - text-decoration: none; -} - -/* ===== RESPONSIVE DESIGN ===== */ -@media (max-width: 768px) { - .navbar { - padding: 0.6rem 1rem; - } - - .navbar-mobile-toggle { - display: block; - } - - .navbar-right { - position: fixed; - top: 0; - right: -100%; - flex-direction: column; - background-color: rgba(12, 59, 93, 0.98); - height: 100vh; - width: 70%; - max-width: 300px; - padding-top: 70px; - transition: all 0.3s ease; - z-index: 15; - gap: 20px; - backdrop-filter: blur(10px); - box-shadow: -5px 0 15px rgba(0, 0, 0, 0.2); - visibility: hidden; - opacity: 0; - } - - .navbar-right.mobile-active { - right: 0; - visibility: visible; - opacity: 1; - } - - .navbar-mobile-toggle.active span:nth-child(1) { - transform: translateY(8px) rotate(45deg); - } - - .navbar-mobile-toggle.active span:nth-child(2) { - opacity: 0; - transform: scale(0); - } - - .navbar-mobile-toggle.active span:nth-child(3) { - transform: translateY(-8px) rotate(-45deg); - } - - .hero-title { - font-size: 2.5rem; - } - - .hero-subtitle { - font-size: 1.2rem; - } - - .section-title { - font-size: 2rem; - } - - .section-subtitle { - font-size: 1.1rem; - } - - .page-section { - padding: 2rem 1.2rem; - } - - .about-section { - padding: 2.5rem 1.2rem; - } - - .about-image-container { - max-width: 140px; - margin-bottom: 1.5rem; - } - - .accordion-header { - padding: 1rem 1.2rem; - font-size: 1rem; - } - - .accordion-item.active .accordion-content { - padding: 1.2rem; - } - - .accordion-toggle-icon { - font-size: 1.1rem; - } - - .icebergs-container { - min-height: auto; - padding: 1rem 0; - } - - .iceberg { - width: 220px; - height: 180px; - margin: 1rem auto; - } - - .iceberg img { - width: 100%; - max-width: 220px; - max-height: 180px; - } - - .service-name { - font-size: 1.2rem; - padding: 10px 16px; - min-width: 150px; - } - - .footer { - padding: 3rem 1.5rem 1.5rem; - } - - .footer-column { - padding: 0 1rem; - } - - .tech-features-grid { - grid-template-columns: 1fr; - } - - .tech-feature-card { - margin-bottom: 1.5rem; - } -} - -@media (max-width: 480px) { - .hero-title { - font-size: 2rem; - } - - .hero-subtitle { - font-size: 1.1rem; - } - - .cta-button { - min-width: auto; - width: 100%; - padding: 0.8rem 1.5rem; - } - - .iceberg { - width: 180px; - height: 150px; - } - - .iceberg img { - max-width: 180px; - max-height: 150px; - } - - .service-name { - font-size: 1.1rem; - padding: 8px 14px; - } -} - -@media (min-width: 769px) and (max-width: 1024px) { - .icebergs-container { - gap: 3%; - } - - .iceberg { - width: 230px; - height: 180px; - } - - .tech-features-grid { - grid-template-columns: repeat(2, 1fr); - } -} +/* This file is no longer needed - all styles have been converted to Tailwind CSS */ diff --git a/banquise-website/src/App.tsx b/banquise-website/src/App.tsx index 2510d95..e6ea4ea 100644 --- a/banquise-website/src/App.tsx +++ b/banquise-website/src/App.tsx @@ -1,522 +1,106 @@ -import { FiUser, FiDatabase, FiShield, FiChevronDown } from 'react-icons/fi' -import { FaDiscord, FaArrowRight, FaEnvelope, FaGithub, FaNetworkWired, FaServer, FaLaptopCode, FaCloudUploadAlt, FaExternalLinkAlt } from 'react-icons/fa' -import { FiX, FiExternalLink } from 'react-icons/fi' -import './App.css' -import icebergImage from './assets/iceberg.png' -import logoImage from './assets/banquise_server.svg' -import { useEffect, useState, useMemo, useCallback, useRef } from 'react' +import React, { useState } from 'react'; +import { Navigation } from './components/layout/Navigation'; +import { Footer } from './components/layout/Footer'; +import { HeroSection } from './components/sections/HeroSection'; +import { TechFeaturesSection } from './components/sections/TechFeaturesSection'; +import { ServicesSection } from './components/sections/ServicesSection'; +import { AboutSection } from './components/sections/AboutSection'; +import { Popup } from './components/ui/Popup'; +import { ScrollToTopButton } from './components/ui/ScrollToTopButton'; +import { URLS } from './config/constants'; -import aboutImage from './assets/banquise.png' - -function App() { - const [selectedService, setSelectedService] = useState(null); - const [mobileMenuOpen, setMobileMenuOpen] = useState(false); - const mobileMenuRef = useRef(null); - - const services = useMemo(() => [ - { - name: "Wiki", - url: "https://wiki.la-banquise.fr/", - description: "Une instance de wikijs, ou nous essayons de documenter nos projets, nos services ou encore notre infra, et aussi des petits tutoriels pour bien comprendre les outils utilises a EPITA !" - }, - { - name: "Git", - url: "https://git.la-banquise.fr/", - description: "Gitea est notre plateforme de gestion de code source, similaire à GitHub, hébergée par nos soins. Nos divers projets necessitant Git, comme par exemple ce site, sont heberges et développes grace a cet outil." - }, - { - name: "Panel jeux", - url: "https://panel.la-banquise.fr/auth/login", - description: "Interface de connection à notre panel Pterodactyl, qui vous permet de gérer vos serveurs de jeux. Celui ci sera remplace dans l ete par pelican." - }, - ], []); - - const [icebergs, setIcebergs] = useState>([]) - - const [reducedMotion, setReducedMotion] = useState(false); - - useEffect(() => { - const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; - setReducedMotion(prefersReducedMotion); - - const startTime = performance.now(); - let count = 0; - while (performance.now() - startTime < 5) { - count++; - } - - if (count < 1000) { - setReducedMotion(true); - } - }, []); - - const positionIcebergs = useCallback(() => { - const newIcebergs = []; - - const positions = [ - { x: 25, y: 35, scale: 0.95, rotation: 0 }, - { x: 50, y: 25, scale: 1.1, rotation: 0 }, - { x: 75, y: 35, scale: 0.95, rotation: 0 }, - ]; - - const floatClasses = ['float-1', 'float-2', 'float-3', 'float-4', 'float-5']; - - for (let i = 0; i < services.length; i++) { - const position = positions[i % positions.length]; - - newIcebergs.push({ - id: i, - x: position.x, - y: position.y, - scale: position.scale, - rotation: position.rotation, - service: services[i], - floatClass: reducedMotion ? '' : floatClasses[i % floatClasses.length] - }); - } - - return newIcebergs; - }, [services, reducedMotion]); - - useEffect(() => { - setIcebergs(positionIcebergs()); - }, [positionIcebergs]); - - const renderBubbles = useMemo(() => { - if (reducedMotion) return null; - - return ( -
-
-
-
-
-
-
-
-
- ); - }, [reducedMotion]); - - const handleIcebergClick = (event: React.MouseEvent, serviceId: number) => { - event.preventDefault(); - setSelectedService(serviceId); - }; - - const handleClosePopup = () => { - setSelectedService(null); - }; - - useEffect(() => { - const handleOutsideClick = (event: MouseEvent) => { - if (mobileMenuRef.current && !mobileMenuRef.current.contains(event.target as Node)) { - setMobileMenuOpen(false); - } - }; - - if (mobileMenuOpen) { - document.addEventListener('mousedown', handleOutsideClick); - } - - return () => { - document.removeEventListener('mousedown', handleOutsideClick); - }; - }, [mobileMenuOpen]); - - useEffect(() => { - if (mobileMenuOpen) { - document.body.style.overflow = 'hidden'; - } else { - document.body.style.overflow = 'auto'; - } - - return () => { - document.body.style.overflow = 'auto'; - }; - }, [mobileMenuOpen]); - - const [activeAccordion, setActiveAccordion] = useState(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 :

-
    -
  1. Connectez-vous au service souhaité avec vos identifiants, pour le moment crees par un admin
  2. -
  3. Consultez notre Wiki pour obtenir de l'aide sur l'utilisation de chaque service !
  4. -
-

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} - -
-
-
-
-
-
-
- -
- Logo La Banquise -
-

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 -

- -
-
- Logo La Banquise -
- -

- 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 && ( -
-
e.stopPropagation()}> - - -

{services[selectedService].description}

- - - Accéder au service - -
-
- )} - - -
-
- - -
- ); +// 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 */} +
+
+
+
+ Logo +
+
+ + {SITE_CONFIG.name} + +

Menu Navigation

+
+
+ + +
+ + {/* Navigation */} + + + {/* 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 ( + <> + + + {/* 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 = () => ( +
+
+ Logo La Banquise +
+ +

+ 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} + + ▼ + +
+
+
+ {children} +
+
+
+); 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) => ( +
+
+
+
+ {feature} +
+ ))} +
+ + {/* Call to action */} +
+ + 🚀 + Accéder à {service.name} + + +

+ Besoin d'aide ? Rejoignez notre Discord pour obtenir du support +

+
+
+
+ + {/* 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 ( + + ); +}; 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