diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml
new file mode 100644
index 0000000..9c31713
--- /dev/null
+++ b/.gitea/workflows/build.yaml
@@ -0,0 +1,78 @@
+name: Build and Test
+run-name: Website build validation
+
+on:
+ push:
+ branches: [main, dev]
+ pull_request:
+ branches: [main, dev]
+
+jobs:
+ build-classic:
+ runs-on: ubuntu-latest
+ name: Classic Build
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+
+ - uses: pnpm/action-setup@v4
+ with:
+ version: 8
+
+ - name: Install and build
+ run: |
+ cd banquise-website
+ pnpm install --frozen-lockfile
+ pnpm build
+
+ - name: Lint check
+ run: |
+ cd banquise-website
+ pnpm lint
+
+ build-docker:
+ runs-on: ubuntu-latest
+ name: Docker Build
+ needs: build-classic
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: docker/setup-buildx-action@v3
+
+ - name: Create Dockerfile if missing
+ run: |
+ cd banquise-website
+ if [ ! -f "Dockerfile" ]; then
+ cat > Dockerfile << 'EOF'
+ FROM node:20-alpine AS builder
+ RUN npm install -g pnpm
+ WORKDIR /app
+ COPY package.json pnpm-lock.yaml ./
+ RUN pnpm install --frozen-lockfile
+ COPY . .
+ RUN pnpm build
+
+ FROM node:20-alpine AS runner
+ RUN npm install -g pnpm
+ WORKDIR /app
+ COPY package.json pnpm-lock.yaml ./
+ RUN pnpm install --frozen-lockfile --prod
+ COPY --from=builder /app/.next ./.next
+ COPY --from=builder /app/public ./public
+ EXPOSE 3000
+ CMD ["pnpm", "start"]
+ EOF
+ fi
+
+ - name: Build and test Docker image
+ run: |
+ cd banquise-website
+ docker build -t banquise-website:test .
+ docker run -d --name test-container -p 3000:3000 banquise-website:test
+ sleep 5
+ docker ps | grep test-container
+ docker stop test-container
+ docker rm test-container
diff --git a/.gitignore b/.gitignore
index 2b20434..3a670d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@
# dotenv environment files (si tu en as)
.env
.env.*.local
+.next
# system files
.DS_Store
@@ -30,7 +31,3 @@ pnpm-debug.log*
# optional: nix store link if using nix develop
.result
-
-# optional: lockfiles you don't use
-package-lock.json
-
diff --git a/README.md b/README.md
index 694c8a0..9f6c91b 100644
--- a/README.md
+++ b/README.md
@@ -1,66 +1,47 @@
# Website Front pour Banquise
-Ce projet est une application web React développée avec Vite, TypeScript et TailwindCSS.
-
-## Architecture du Projet
-
-```
-website-front/
-├── banquise-website/ # Application React principale
-│ ├── public/ # Fichiers statiques
-│ ├── src/ # Code source
-│ │ ├── assets/ # Images et ressources
-│ │ ├── App.tsx # Composant principal
-│ │ └── main.tsx # Point d'entrée de l'application
-│ ├── index.html # Template HTML principal
-│ ├── package.json # Configuration des dépendances
-│ ├── tsconfig.json # Configuration TypeScript
-│ ├── vite.config.ts # Configuration Vite
-│ └── tailwind.config.js # Configuration TailwindCSS
-└── shell.nix # Configuration pour environnement Nix
-```
-
-## Technologies Utilisées
-
-- **React 18** - Bibliothèque d'interface utilisateur
-- **TypeScript** - Langage de programmation typé
-- **Vite** - Outil de build et serveur de développement
-- **TailwindCSS** - Framework CSS utilitaire
-- **React Router** - Navigation entre les pages
-- **Zustand** - Gestion d'état
-- **React Query** - Gestion des requêtes API
-- **Framer Motion** - Animations
+Depôt officiel du site internet de l'association "La Banquise" développé avec Next.js
## Pré-requis
-- Node.js (v16.0.0 ou supérieur)
-- npm ou yarn
+- Node.js (v18+ recommandé)
+- `pnpm` (utilisé pour le gestionnaire de paquets)
-## Installation
+## Utilisation
+### Mode développement
+Naviguer à la racine du site internet
```bash
-# Se déplacer dans le dossier du projet
cd banquise-website
-
-# Installer les dépendances
-npm install
-# ou avec yarn
-yarn
```
-## Scripts Disponibles
-
-- `npm run dev` - Lance le serveur de développement
-- `npm run build` - Compile le projet pour la production
-- `npm run preview` - Prévisualise la version de production localement
-- `npm run lint` - Vérifie la qualité du code avec ESLint
-
-## Déploiement
-
-### Compilation pour la Production
-
+Installer toutes les dépendences nécéssaires
```bash
-npm run build
+pnpm install
```
-Cette commande générera un dossier `dist` dans le répertoire `banquise-website/` contenant tous les fichiers optimisés pour la production.
\ No newline at end of file
+Executer le serveur de developpement
+```bash
+pnpm dev
+```
+
+Acceder au site internet
+```bash
+http://localhost:3000
+```
+
+### Mode production
+Naviguer à la racine du projet
+```bash
+cd banquise-website
+```
+
+Build l'image Docker
+```bash
+docker build -t banquise-website .
+```
+
+Executer l'image Docker en mode detach
+```bash
+docker run -p 3000:3000 -d banquise-website
+```
\ No newline at end of file
diff --git a/banquise-website/.gitignore b/banquise-website/.gitignore
index a547bf3..047da3c 100644
--- a/banquise-website/.gitignore
+++ b/banquise-website/.gitignore
@@ -1,3 +1,159 @@
+# Dependencies
+node_modules/
+.pnp
+.pnp.js
+
+# Testing
+coverage/
+.nyc_output
+
+# Next.js
+.next/
+out/
+build/
+dist/
+
+# Production builds
+*.tgz
+*.tar.gz
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Coverage directory used by tools like istanbul
+coverage/
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage
+.grunt
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons
+build/Release
+
+# Dependency directories
+jspm_packages/
+
+# Snowpack dependency directory
+web_modules/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional stylelint cache
+.stylelintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variable files
+.env
+.env.development.local
+.env.test.local
+.env.production.local
+.env.local
+
+# parcel-bundler cache
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+out
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+public
+
+# Vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+.vscode-test
+
+# yarn v2
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+
+# IntelliJ based IDEs
+.idea
+
+# Finder (MacOS)
+.DS_Store
+
+# Windows
+Thumbs.db
+ehthumbs.db
+Desktop.ini
+
+# VS Code
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+!.vscode/*.code-snippets
+
+# Local History for Visual Studio Code
+.history/
+
+# Built Visual Studio Code Extensions
+*.vsix
+
+# ESLint cache
+.eslintcache
+
+# Prettier cache
+.prettiercache
+
+# Stylelint cache
+.stylelintcache
+
# Logs
logs
*.log
@@ -7,18 +163,79 @@ yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
-node_modules
-dist
-dist-ssr
-*.local
+# Diagnostic reports
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# Dependency directories
+node_modules/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# next.js build output
+.next
+
+# nuxt.js build output
+.nuxt
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Temporary folders
+tmp/
+temp/
+
+# Editor backup files
+*~
+*.swp
+*.swo
+
+# OS generated files
.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+
+# Local environment files
+.env*.local
diff --git a/banquise-website/Dockerfile b/banquise-website/Dockerfile
new file mode 100644
index 0000000..79416c0
--- /dev/null
+++ b/banquise-website/Dockerfile
@@ -0,0 +1,38 @@
+# Stage 1: install deps and build
+FROM node:20-alpine AS builder
+WORKDIR /app
+
+# Install pnpm
+RUN corepack enable && corepack prepare pnpm@latest --activate
+
+# Copy manifests
+COPY package.json pnpm-lock.yaml* ./
+
+# Install deps
+RUN pnpm install --prod=false
+
+# Copy source
+COPY . .
+
+# Build
+RUN pnpm build
+
+# Stage 2: production image
+FROM node:20-alpine AS runner
+WORKDIR /app
+
+ENV NODE_ENV=production
+ENV PORT=3000
+
+# Install pnpm runtime
+RUN corepack enable && corepack prepare pnpm@latest --activate
+
+# Copy only production files
+COPY --from=builder /app/package.json ./package.json
+COPY --from=builder /app/.next ./.next
+COPY --from=builder /app/public ./public
+COPY --from=builder /app/node_modules ./node_modules
+
+EXPOSE 3000
+
+CMD ["pnpm", "start"]
diff --git a/banquise-website/README.md b/banquise-website/README.md
deleted file mode 100644
index da98444..0000000
--- a/banquise-website/README.md
+++ /dev/null
@@ -1,54 +0,0 @@
-# React + TypeScript + Vite
-
-This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
-
-Currently, two official plugins are available:
-
-- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
-- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
-
-## Expanding the ESLint configuration
-
-If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
-
-```js
-export default tseslint.config({
- extends: [
- // Remove ...tseslint.configs.recommended and replace with this
- ...tseslint.configs.recommendedTypeChecked,
- // Alternatively, use this for stricter rules
- ...tseslint.configs.strictTypeChecked,
- // Optionally, add this for stylistic rules
- ...tseslint.configs.stylisticTypeChecked,
- ],
- languageOptions: {
- // other options...
- parserOptions: {
- project: ['./tsconfig.node.json', './tsconfig.app.json'],
- tsconfigRootDir: import.meta.dirname,
- },
- },
-})
-```
-
-You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
-
-```js
-// eslint.config.js
-import reactX from 'eslint-plugin-react-x'
-import reactDom from 'eslint-plugin-react-dom'
-
-export default tseslint.config({
- plugins: {
- // Add the react-x and react-dom plugins
- 'react-x': reactX,
- 'react-dom': reactDom,
- },
- rules: {
- // other rules...
- // Enable its recommended typescript rules
- ...reactX.configs['recommended-typescript'].rules,
- ...reactDom.configs.recommended.rules,
- },
-})
-```
diff --git a/banquise-website/app/globals.css b/banquise-website/app/globals.css
new file mode 100644
index 0000000..2f9eebd
--- /dev/null
+++ b/banquise-website/app/globals.css
@@ -0,0 +1,126 @@
+@import "tailwindcss";
+
+/* Configuration Tailwind v4 via CSS custom properties - Variables globales */
+@layer base {
+ :root {
+ /* Polices */
+ --font-heading: 'Dela Gothic One', sans-serif;
+ --font-body: 'Roboto', sans-serif;
+
+ /* Couleurs personnalisées La Banquise */
+ --color-banquise-blue: 64, 180, 255;
+ --color-banquise-blue-hex: #40B4FF;
+ --color-banquise-blue-dark: 31, 93, 137;
+ --color-banquise-blue-dark-hex: #1F5D89;
+ --color-banquise-blue-light: 105, 183, 226;
+ --color-banquise-blue-light-hex: #69B7E2;
+ --color-banquise-blue-lightest: 165, 240, 255;
+ --color-banquise-blue-lightest-hex: #A5F0FF;
+ --color-banquise-gray: #F6F6F6;
+
+ /* Couleurs Discord officielles */
+ --color-discord-blurple: #5865F2;
+ --color-discord-dark: #4752C4;
+ --color-discord-old-blurple: #7289DA;
+ --color-discord-old-dark: #5B6EAE;
+
+ /* Transitions communes */
+ --transition-default: all 0.3s ease-in-out;
+ --transition-fast: all 0.2s ease-in-out;
+
+ /* Spacing commun */
+ --spacing-navbar: 4rem;
+ }
+}
+
+/* Minimal, valid utility helpers avec variables optimisées */
+@layer utilities {
+ /* Text colors */
+ .text-banquise-blue { color: var(--color-banquise-blue-hex); }
+ .text-banquise-blue-dark { color: var(--color-banquise-blue-dark-hex); }
+ .text-banquise-blue-light { color: var(--color-banquise-blue-light-hex); }
+ .text-banquise-blue-lightest { color: var(--color-banquise-blue-lightest-hex); }
+ .text-banquise-gray { color: var(--color-banquise-gray); }
+ .text-discord { color: var(--color-discord-blurple); }
+
+ /* Background colors */
+ .bg-banquise-blue { background-color: var(--color-banquise-blue-hex); }
+ .bg-banquise-blue-dark { background-color: var(--color-banquise-blue-dark-hex); }
+ .bg-banquise-blue-light { background-color: var(--color-banquise-blue-light-hex); }
+ .bg-banquise-blue-lightest { background-color: var(--color-banquise-blue-lightest-hex); }
+ .bg-banquise-gray { background-color: var(--color-banquise-gray); }
+ .bg-discord { background-color: var(--color-discord-blurple); }
+
+ /* Opacity helpers using rgba() */
+ .bg-banquise-blue-5 { background-color: rgba(var(--color-banquise-blue), 0.05); }
+ .bg-banquise-blue-10 { background-color: rgba(var(--color-banquise-blue), 0.10); }
+ .bg-banquise-blue-20 { background-color: rgba(var(--color-banquise-blue), 0.20); }
+ .bg-banquise-blue-dark-10 { background-color: rgba(var(--color-banquise-blue-dark), 0.10); }
+
+ /* Border colors */
+ .border-banquise-blue { border-color: var(--color-banquise-blue-hex); }
+ .border-banquise-blue-lightest-30 { border-color: rgba(var(--color-banquise-blue-lightest), 0.3); }
+
+ /* Gradients shortcuts */
+ .from-banquise-blue { --tw-gradient-from: var(--color-banquise-blue-hex); }
+ .from-banquise-blue-dark { --tw-gradient-from: var(--color-banquise-blue-dark-hex); }
+ .via-banquise-blue { --tw-gradient-via: var(--color-banquise-blue-hex); }
+ .to-banquise-blue { --tw-gradient-to: var(--color-banquise-blue-hex); }
+
+ /* Shadow helpers */
+ .shadow-banquise-blue-20 { box-shadow: 0 4px 6px -1px rgba(var(--color-banquise-blue), 0.20); }
+
+ /* Transitions communes */
+ .transition-default { transition: var(--transition-default); }
+ .transition-fast { transition: var(--transition-fast); }
+}
+
+/* Animations optimisées */
+@keyframes gentle-float {
+ 0%, 100% { transform: translateY(0) rotate(0deg); }
+ 50% { transform: translateY(-15px) rotate(1deg); }
+}
+
+@keyframes bounce-up {
+ 0%, 100% { transform: translateY(0); }
+ 50% { transform: translateY(-4px); }
+}
+
+.animate-gentle-float { animation: gentle-float 6s ease-in-out infinite; }
+.scroll-to-top:hover { animation: bounce-up 0.6s ease-in-out; }
+
+/* Configuration globale optimisée */
+@media (prefers-reduced-motion: reduce) {
+ .animate-gentle-float,
+ .animate-ping,
+ .animate-pulse {
+ animation: none !important;
+ }
+}
+
+html { scroll-behavior: smooth; }
+body { overflow-x: hidden; }
+
+/* Scrollbar unifié pour tous les éléments */
+.custom-scrollbar,
+.popup-content {
+ scrollbar-width: thin;
+ scrollbar-color: rgba(31,93,137,0.3) transparent;
+}
+
+.custom-scrollbar::-webkit-scrollbar,
+.popup-content::-webkit-scrollbar { width: 6px; }
+
+.custom-scrollbar::-webkit-scrollbar-track,
+.popup-content::-webkit-scrollbar-track { background: transparent; }
+
+.custom-scrollbar::-webkit-scrollbar-thumb,
+.popup-content::-webkit-scrollbar-thumb {
+ background: rgba(31,93,137,0.3);
+ border-radius: 3px;
+}
+
+.custom-scrollbar::-webkit-scrollbar-thumb:hover,
+.popup-content::-webkit-scrollbar-thumb:hover {
+ background: rgba(31,93,137,0.5);
+}
diff --git a/banquise-website/app/layout.tsx b/banquise-website/app/layout.tsx
new file mode 100644
index 0000000..6f123f9
--- /dev/null
+++ b/banquise-website/app/layout.tsx
@@ -0,0 +1,18 @@
+import './globals.css'
+import type { ReactNode } from 'react'
+
+export const metadata = {
+ title: 'La Banquise - Hébergement et Communauté Tech',
+ description: "Association d'hébergement et lab réseau pour tous les étudiants et associations de l'EPITA. Services Wiki, Gitea, Panel de jeux.",
+}
+
+export default function RootLayout({ children }: { children: ReactNode }) {
+ return (
+
+
+ {children}
+
+
+ )
+}
diff --git a/banquise-website/app/page.tsx b/banquise-website/app/page.tsx
new file mode 100644
index 0000000..cc4f8b9
--- /dev/null
+++ b/banquise-website/app/page.tsx
@@ -0,0 +1,108 @@
+"use client"
+import React from 'react';
+import { ModernNavigation } from '@/components/layout/ModernNavigation';
+import { HeroSection } from '@/components/sections/HeroSection';
+import { ServicesSection } from '@/components/sections/ServicesSection';
+import { TechFeaturesSection } from '@/components/sections/TechFeaturesSection';
+import { AboutSection } from '@/components/sections/AboutSection';
+import { Footer } from '@/components/layout/Footer';
+import { Popup } from '@/components/ui/Popup';
+import { ScrollToTopButton } from '@/components/ui/ScrollToTopButton';
+import { ModernLanguageSwitcher } from '@/components/ui/ModernLanguageSwitcher';
+import { OceanBackground } from '@/components/ui/OceanBackground';
+import { useTranslation } from '@/lib/hooks/useTranslation';
+import { useServiceModal } from '@/lib/hooks/useServiceModal';
+import { useAccordion } from '@/lib/hooks/useAccordion';
+
+export default function HomePage() {
+ const { t, currentLanguage, changeLanguage, availableLanguages } = useTranslation();
+ const { selectedService, openServiceModal, closeServiceModal } = useServiceModal();
+ const { openAccordion, toggleAccordion } = useAccordion();
+
+ return (
+
+ {/* Navigation */}
+
+ }
+ />
+
+ {/* Hero Section avec motif de grille */}
+
+
+ {/* Services Section avec transition subtile */}
+
+
+ {/* Tech Features Section avec motif de grille */}
+
+
+ {/* About Section avec transition moderne */}
+
{/* Footer - Même couleur que navbar */}
+
+
+ {/* UI Components */}
+
+
+ {selectedService && (
+
+ )}
+
+ );
+}
diff --git a/banquise-website/build.sh b/banquise-website/build.sh
deleted file mode 100755
index 734716c..0000000
--- a/banquise-website/build.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-npm install
-npm run build
diff --git a/banquise-website/components/common/Button.tsx b/banquise-website/components/common/Button.tsx
new file mode 100644
index 0000000..26db144
--- /dev/null
+++ b/banquise-website/components/common/Button.tsx
@@ -0,0 +1,74 @@
+import React from 'react';
+import { cn, commonClasses } from '@/lib/utils';
+
+interface ButtonProps extends React.ButtonHTMLAttributes {
+ variant?: 'primary' | 'discord' | 'auth' | 'secondary' | 'ghost' | 'outline';
+ size?: 'sm' | 'md' | 'lg';
+ fullWidth?: boolean;
+ leftIcon?: React.ReactNode;
+ rightIcon?: React.ReactNode;
+ loading?: boolean;
+ children: React.ReactNode;
+}
+
+// Factorisation des classes de taille et de variante
+const sizeClasses = {
+ sm: 'px-4 py-2 text-sm',
+ md: 'px-6 py-3 text-base',
+ lg: 'px-8 py-4 text-lg',
+} as const;
+
+const variantClasses = {
+ primary: 'bg-gradient-to-r from-blue-600 to-blue-500 text-white shadow-lg hover:shadow-xl hover:from-blue-700 hover:to-blue-600 border-2 border-blue-600/20',
+ discord: 'bg-gradient-to-r from-[#5865F2] to-[#7289DA] text-white shadow-lg hover:shadow-xl hover:from-[#4752C4] hover:to-[#5B6EAE] border-2 border-[#5865F2]/20',
+ auth: 'bg-gradient-to-r from-blue-500 to-blue-400 text-white shadow-lg hover:shadow-xl hover:from-blue-600 hover:to-blue-500 border-2 border-blue-500/20',
+ secondary: 'bg-white text-blue-700 border-2 border-blue-600 shadow-md hover:shadow-lg hover:bg-blue-50',
+ outline: 'bg-transparent text-gray-700 border-2 border-gray-300 hover:bg-gray-50 hover:border-gray-400',
+ ghost: 'bg-transparent text-gray-700 hover:bg-gray-100',
+} as const;
+
+// Composant loading spinner réutilisable
+const LoadingSpinner = () => (
+
+
+
+
+);
+
+export const Button: React.FC = ({
+ variant = 'primary',
+ size = 'md',
+ fullWidth = false,
+ leftIcon,
+ rightIcon,
+ loading = false,
+ children,
+ className = '',
+ disabled,
+ ...props
+}) => {
+ const isDisabled = disabled || loading;
+
+ return (
+
+ {loading && }
+ {leftIcon && !loading && {leftIcon} }
+ {children}
+ {rightIcon && !loading && {rightIcon} }
+
+ );
+};
diff --git a/banquise-website/components/common/ServiceCard.tsx b/banquise-website/components/common/ServiceCard.tsx
new file mode 100644
index 0000000..bb08063
--- /dev/null
+++ b/banquise-website/components/common/ServiceCard.tsx
@@ -0,0 +1,114 @@
+import React from 'react';
+import Image from 'next/image'
+import { cn, commonClasses } from '@/lib/utils';
+import type { Service } from '@/types/service';
+
+interface ServiceCardProps {
+ service: Service;
+ onServiceClick: (service: Service) => void;
+ className?: string;
+}
+
+// Composant pour l'icône de flèche factorisant la structure répétitive
+const HoverArrow = () => (
+
+);
+
+export const ServiceCard: React.FC = ({
+ service,
+ onServiceClick,
+ className = '',
+}) => {
+ const handleClick = () => {
+ onServiceClick(service);
+ };
+
+ return (
+
+ {/* Indicateur de survol */}
+
+
+ {/* Contenu de la carte */}
+
+ {/* Icône du service */}
+
+ {service.iconType === 'image' ? (
+
+ ) : service.lucideIcon ? (
+
+ ) : (
+
+ )}
+
+
+ {/* Nom du service */}
+
+ {service.name}
+
+
+ {/* Description courte */}
+
+ {service.description.split('.')[0]}.
+
+
+ {/* Flèche indicatrice au hover */}
+
+
+
+ );
+};
diff --git a/banquise-website/components/common/UserProfile.tsx b/banquise-website/components/common/UserProfile.tsx
new file mode 100644
index 0000000..3a30305
--- /dev/null
+++ b/banquise-website/components/common/UserProfile.tsx
@@ -0,0 +1,177 @@
+import React, { useState, useRef, useEffect } from 'react';
+import Image from 'next/image';
+import { useTranslation } from '@/lib/hooks/useTranslation';
+import type { AutheliaUser } from '@/lib/services/auth';
+
+// Fonction utilitaire simple pour combiner les classes
+const cn = (...classes: (string | undefined | null | false)[]): string => {
+ return classes.filter(Boolean).join(' ');
+};
+
+interface UserProfileProps {
+ user: AutheliaUser;
+ onLogout: () => void;
+ className?: string;
+}
+
+export const UserProfile: React.FC = ({
+ user,
+ onLogout,
+ className,
+}) => {
+ const [isOpen, setIsOpen] = useState(false);
+ const dropdownRef = useRef(null);
+ const buttonRef = useRef(null);
+ const { t } = useTranslation();
+ const defaultAvatarSmall = `https://ui-avatars.com/api/?name=${encodeURIComponent(user.name)}&background=0ea5e9&color=fff&size=32`;
+ const defaultAvatarLarge = `https://ui-avatars.com/api/?name=${encodeURIComponent(user.name)}&background=0ea5e9&color=fff&size=40`;
+ const avatarSrc = user.avatar ?? defaultAvatarSmall;
+ const avatarLargeSrc = user.avatar ?? defaultAvatarLarge;
+
+ // Fermer la popup en cliquant à l'extérieur
+ useEffect(() => {
+ const handleClickOutside = (event: MouseEvent) => {
+ if (
+ dropdownRef.current &&
+ buttonRef.current &&
+ !dropdownRef.current.contains(event.target as Node) &&
+ !buttonRef.current.contains(event.target as Node)
+ ) {
+ setIsOpen(false);
+ }
+ };
+
+ document.addEventListener('mousedown', handleClickOutside);
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside);
+ };
+ }, []);
+
+ const handleLogout = async () => {
+ setIsOpen(false);
+ onLogout();
+ };
+
+ return (
+
+ {/* Bouton Avatar */}
+
setIsOpen(!isOpen)}
+ className={cn(
+ 'flex items-center justify-center w-8 h-8 rounded-full overflow-hidden',
+ 'border-2 border-transparent hover:border-blue-300',
+ 'transition-all duration-200',
+ 'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2',
+ isOpen && 'ring-2 ring-blue-500 ring-offset-2'
+ )}
+ aria-label={t.user.userMenu}
+ >
+
+
+
+ {/* Popup Menu */}
+ {isOpen && (
+
+ {/* Header avec informations utilisateur */}
+
+
+
+
+
+ {user.name}
+
+
+ {user.email}
+
+
+
+
+
+ {/* Groupes utilisateur (si disponibles) */}
+ {user.groups && user.groups.length > 0 && (
+
+
{t.user.groups}
+
+ {user.groups.map((group, index) => (
+
+ {group}
+
+ ))}
+
+
+ )}
+
+ {/* Actions */}
+
+
+
+
+
+ {t.user.logout}
+
+
+
+ )}
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/banquise-website/components/layout/Footer.tsx b/banquise-website/components/layout/Footer.tsx
new file mode 100644
index 0000000..7567ddc
--- /dev/null
+++ b/banquise-website/components/layout/Footer.tsx
@@ -0,0 +1,151 @@
+import React from 'react';
+import { URLS, SITE_CONFIG } from '@/lib/config/constants';
+import { BookOpen, GitBranch, Gamepad2, Cloud, Rocket, Heart } from 'lucide-react';
+import { useTranslation } from '@/lib/hooks/useTranslation';
+import { cn, commonClasses } from '@/lib/utils';
+import { DiscordIcon } from '@/components/ui/DiscordLogo';
+
+const EmailIcon = () => (
+
+
+
+);
+
+// Composant pour les liens de service factorisant la structure répétitive
+interface ServiceLinkProps {
+ href: string;
+ icon: React.ComponentType;
+ children: React.ReactNode;
+}
+
+const ServiceLink: React.FC = ({ href, icon: Icon, children }) => (
+
+
+ {children}
+
+);
+
+// Composant pour les boutons sociaux factorisant la structure répétitive
+interface SocialButtonProps {
+ href: string;
+ label: string;
+ children: React.ReactNode;
+}
+
+const SocialButton: React.FC = ({ href, label, children }) => (
+
+ {children}
+
+);
+
+export const Footer: React.FC = () => {
+ const { t } = useTranslation();
+
+ return (
+
+ );
+};
diff --git a/banquise-website/components/layout/MobileMenu.tsx b/banquise-website/components/layout/MobileMenu.tsx
new file mode 100644
index 0000000..1104a39
--- /dev/null
+++ b/banquise-website/components/layout/MobileMenu.tsx
@@ -0,0 +1,160 @@
+import React, { useEffect } from 'react';
+import { Logo } from './navbar/Logo';
+import { useTranslation } from '@/lib/hooks/useTranslation';
+import { URLS } from '@/lib/config/constants';
+import { cn, createNavClickHandler } from '@/lib/utils';
+import { DiscordLogo } from '@/components/ui/DiscordLogo';
+import type { Translation } from '@/types/i18n';
+
+interface MobileMenuProps {
+ isOpen: boolean;
+ onClose: () => void;
+ translations: Translation['navigation'];
+}
+
+interface MobileNavItemProps {
+ title: string;
+ href: string;
+ isExternal?: boolean;
+ onClick?: () => void;
+ isDiscord?: boolean;
+}
+
+const MobileNavItem: React.FC = ({
+ title,
+ href,
+ isExternal = false,
+ onClick,
+ isDiscord = false
+}) => {
+ const handleClick = (e: React.MouseEvent) => {
+ if (onClick) {
+ e.preventDefault();
+ onClick();
+ }
+ };
+
+ return (
+
+
+ {isDiscord && }
+ {title}
+
+ {isExternal && (
+
+
+
+ )}
+
+ );
+};
+
+export const MobileMenu: React.FC = ({ isOpen, onClose, translations }) => {
+ const { t } = useTranslation();
+
+ // Gérer le scroll du body
+ useEffect(() => {
+ if (isOpen) {
+ document.body.style.overflow = 'hidden';
+ } else {
+ document.body.style.overflow = 'unset';
+ }
+
+ return () => {
+ document.body.style.overflow = 'unset';
+ };
+ }, [isOpen]);
+
+ // Gestionnaire de navigation
+ const handleNavClick = createNavClickHandler(onClose);
+
+ return (
+
+ {/* Overlay simple */}
+
+
+ {/* Menu Panel épuré */}
+
+
+ {/* Header simple */}
+
+
+ {/* Navigation simple */}
+
+
handleNavClick('home')}
+ />
+
+ handleNavClick('services')}
+ />
+
+ handleNavClick('about')}
+ />
+
+ handleNavClick('contact')}
+ />
+
+ {/* Séparateur simple */}
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/banquise-website/components/layout/ModernNavigation.tsx b/banquise-website/components/layout/ModernNavigation.tsx
new file mode 100644
index 0000000..02fd6ac
--- /dev/null
+++ b/banquise-website/components/layout/ModernNavigation.tsx
@@ -0,0 +1,73 @@
+import React from 'react';
+import { useScrollEffects } from '@/lib/hooks/useScrollEffects';
+import { Logo } from './navbar/Logo';
+import { NavLinks } from './navbar/NavLinks';
+import { ActionButtons } from './navbar/ActionButtons';
+import { MobileMenuButton } from './navbar/MobileMenuButton';
+import { MobileMenu } from './MobileMenu';
+import { cn, useResizeHandler } from '@/lib/utils';
+import type { Translation } from '@/types/i18n';
+
+interface ModernNavigationProps {
+ translations: Translation['navigation'];
+ languageSwitcher: React.ReactElement;
+}
+
+export const ModernNavigation: React.FC = ({
+ translations,
+ languageSwitcher
+}) => {
+ const { scrolled } = useScrollEffects();
+ const [mobileMenuOpen, setMobileMenuOpen] = React.useState(false);
+
+ // Fermer le menu mobile lors du redimensionnement - optimisé
+ React.useEffect(() => {
+ const cleanup = useResizeHandler(() => setMobileMenuOpen(false));
+ return cleanup;
+ }, []);
+
+ return (
+ <>
+ {/* Navigation moderne épurée */}
+
+
+
+
+
+
+
+
+
+
+
+
+
setMobileMenuOpen(!mobileMenuOpen)}
+ />
+
+
+
+ {/* Ligne de séparation moderne */}
+
+
+
+ {/* Spacer pour compenser la navbar fixed */}
+
+
+ setMobileMenuOpen(false)}
+ translations={translations}
+ />
+ >
+ );
+};
diff --git a/banquise-website/components/layout/navbar/ActionButtons.tsx b/banquise-website/components/layout/navbar/ActionButtons.tsx
new file mode 100644
index 0000000..74c798b
--- /dev/null
+++ b/banquise-website/components/layout/navbar/ActionButtons.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { DiscordButton } from '@/components/ui/DiscordButton';
+
+interface ActionButtonsProps {
+ scrolled: boolean;
+ languageSwitcher: React.ReactElement;
+}
+
+export const ActionButtons: React.FC = ({
+ scrolled,
+ languageSwitcher
+}) => {
+ return (
+
+ {/* Language Switcher */}
+ {languageSwitcher}
+
+ {/* Discord Button */}
+
+ Discord
+
+
+ );
+};
\ No newline at end of file
diff --git a/banquise-website/components/layout/navbar/Logo.tsx b/banquise-website/components/layout/navbar/Logo.tsx
new file mode 100644
index 0000000..f297270
--- /dev/null
+++ b/banquise-website/components/layout/navbar/Logo.tsx
@@ -0,0 +1,64 @@
+import React from 'react';
+import Image from 'next/image';
+import { SITE_CONFIG } from '@/lib/config/constants';
+
+// Fonction utilitaire simple pour combiner les classes
+const mergeClasses = (...classes: (string | undefined | null | false)[]): string => {
+ return classes.filter(Boolean).join(' ');
+};
+
+interface LogoProps {
+ scrolled?: boolean;
+ className?: string;
+}
+
+export const Logo: React.FC = ({ scrolled = false, className }) => {
+ return (
+
+ {/* Logo moderne avec effet subtil */}
+
+ {/* Effet de glow moderne et subtil */}
+
+
+ {/* Container du logo */}
+
+
+
+
+
+ {/* Texte de marque épuré */}
+
+
+ {SITE_CONFIG.name}
+
+
+ {!scrolled && (
+
+ {SITE_CONFIG.tagline}
+
+ )}
+
+
+ );
+};
diff --git a/banquise-website/components/layout/navbar/MobileMenuButton.tsx b/banquise-website/components/layout/navbar/MobileMenuButton.tsx
new file mode 100644
index 0000000..970181a
--- /dev/null
+++ b/banquise-website/components/layout/navbar/MobileMenuButton.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+
+// Fonction utilitaire simple pour combiner les classes
+const cn = (...classes: (string | undefined | null | false)[]): string => {
+ return classes.filter(Boolean).join(' ');
+};
+
+interface MobileMenuButtonProps {
+ isOpen: boolean;
+ onClick: () => void;
+ className?: string;
+}
+
+export const MobileMenuButton: React.FC = ({
+ isOpen,
+ onClick,
+ className
+}) => {
+ return (
+
+ {/* Hamburger Icon avec animation moderne */}
+
+
+
+
+
+
+ {/* Subtle glow effect on hover */}
+
+
+ );
+};
diff --git a/banquise-website/components/layout/navbar/NavLinks.tsx b/banquise-website/components/layout/navbar/NavLinks.tsx
new file mode 100644
index 0000000..ec072ea
--- /dev/null
+++ b/banquise-website/components/layout/navbar/NavLinks.tsx
@@ -0,0 +1,144 @@
+import React from 'react';
+import type { Translation } from '@/types/i18n';
+
+// Fonction utilitaire simple pour combiner les classes
+const mergeClasses = (...classes: (string | undefined | null | false)[]): string => {
+ return classes.filter(Boolean).join(' ');
+};
+
+interface NavLinksProps {
+ translations: Translation['navigation'];
+ scrolled?: boolean;
+ className?: string;
+}
+
+interface NavLinkProps {
+ href: string;
+ children: React.ReactNode;
+ isActive?: boolean;
+ onClick?: () => void;
+}
+
+const NavLink: React.FC = ({ href, children, isActive = false, onClick }) => {
+ return (
+ {
+ e.preventDefault();
+ onClick?.();
+ }}
+ className={mergeClasses(
+ // Base styles
+ 'relative px-4 py-2.5 text-sm font-medium transition-all duration-200 rounded-xl',
+ 'focus:outline-none focus:ring-2 focus:ring-blue-400/50',
+
+ // États conditionnels
+ isActive
+ ? 'text-white bg-white/15 shadow-sm backdrop-blur-sm border border-white/20'
+ : 'text-white/80 hover:text-white hover:bg-white/10'
+ )}
+ >
+ {children}
+
+ {/* Indicateur actif moderne */}
+ {isActive && (
+
+ )}
+
+ );
+};
+
+export const NavLinks: React.FC = ({ translations, className }) => {
+ const [activeSection, setActiveSection] = React.useState('home');
+
+ // Observer pour détecter la section active (simplifié)
+ React.useEffect(() => {
+ const handleScroll = () => {
+ const scrollPosition = window.scrollY;
+
+ // Si on est en haut de la page
+ if (scrollPosition < 200) {
+ setActiveSection('home');
+ return;
+ }
+
+ // Détection des sections
+ const sections = ['services', 'about'];
+ let currentSection = 'home';
+
+ sections.forEach((sectionId) => {
+ const element = document.getElementById(sectionId);
+ if (element) {
+ const rect = element.getBoundingClientRect();
+ if (rect.top <= 200 && rect.bottom >= 200) {
+ currentSection = sectionId;
+ }
+ }
+ });
+
+ setActiveSection(currentSection);
+ };
+
+ window.addEventListener('scroll', handleScroll, { passive: true });
+ handleScroll();
+
+ return () => window.removeEventListener('scroll', handleScroll);
+ }, []);
+
+ const handleNavClick = (sectionId: string) => {
+ if (sectionId === 'home') {
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+ } else if (sectionId === 'contact') {
+ window.location.href = 'mailto:contact@la-banquise.fr';
+ } else {
+ const element = document.getElementById(sectionId);
+ if (element) {
+ const navHeight = 64; // Hauteur de la navbar
+ const elementPosition = element.offsetTop - navHeight;
+ window.scrollTo({
+ top: elementPosition,
+ behavior: 'smooth'
+ });
+ }
+ }
+ };
+
+ return (
+
+ handleNavClick('home')}
+ >
+ {translations.home}
+
+
+ handleNavClick('services')}
+ >
+ {translations.services}
+
+
+ handleNavClick('about')}
+ >
+ {translations.about}
+
+
+ handleNavClick('contact')}
+ >
+ {translations.contact}
+
+
+ );
+};
diff --git a/banquise-website/components/sections/AboutSection.tsx b/banquise-website/components/sections/AboutSection.tsx
new file mode 100644
index 0000000..186887b
--- /dev/null
+++ b/banquise-website/components/sections/AboutSection.tsx
@@ -0,0 +1,171 @@
+import React from 'react';
+import { AccordionItem } from '@/components/ui/AccordionItem';
+import { SectionHeader } from '@/components/ui/SectionHeader';
+import { ServiceCardAbout } from '@/components/ui/ServiceCardAbout';
+import { AccordionTitle } from '@/components/ui/AccordionTitle';
+import { URLS } from '@/lib/config/constants';
+import { Target, Settings, HelpCircle, Users, MessageCircle, Rocket, BookOpen, GitBranch, Gamepad2, Bird, Building, Mail, Cloud } from 'lucide-react';
+import { useTranslation } from '@/lib/hooks/useTranslation';
+import { cn, commonClasses } from '@/lib/utils';
+
+interface AboutSectionProps {
+ openAccordion: string | null;
+ toggleAccordion: (title: string) => void;
+}
+
+export const AboutSection: React.FC = ({ openAccordion, toggleAccordion }) => {
+ const { t } = useTranslation();
+
+ return (
+
+
+ {/* Header de section moderne - factorisation */}
+
+
+ {/* Section FAQ avec design moderne */}
+
+
+
+
+
+ {t.about.faqTitle}
+
+
+
}
+ isOpen={openAccordion === "mission"}
+ onToggle={() => toggleAccordion("mission")}
+ >
+
+
+ {t.about.mission.description1}
+
+
+ {t.about.mission.description2}
+
+
+ {t.about.mission.tags.collaboration}
+ {t.about.mission.tags.innovation}
+ {t.about.mission.tags.accessibility}
+
+
+
+
+
}
+ isOpen={openAccordion === "services"}
+ onToggle={() => toggleAccordion("services")}
+ >
+
+
+ {/* Cartes de services avec design moderne - factorisation */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {t.about.services.title}
+ {t.about.services.note}
+
+
+
+
+
}
+ isOpen={openAccordion === "community"}
+ onToggle={() => toggleAccordion("community")}
+ >
+
+
+ {t.about.community.description}
+
+
+
+
+
+
+
+ {t.about.community.howToJoin}
+
+
+
+
+ {t.about.community.steps.step1}
+
+
+
+ {t.about.community.steps.step2}
+
+
+
+ {t.about.community.steps.step3}
+
+
+
+
+
+ {t.about.community.joinDiscord}
+
+
+
+
+
+
+
+ );
+};
diff --git a/banquise-website/components/sections/HeroSection.tsx b/banquise-website/components/sections/HeroSection.tsx
new file mode 100644
index 0000000..a29d59b
--- /dev/null
+++ b/banquise-website/components/sections/HeroSection.tsx
@@ -0,0 +1,148 @@
+import React from 'react';
+import Image from 'next/image';
+import { ArrowRight } from 'lucide-react';
+import { cn, commonClasses } from '@/lib/utils';
+import type { Translation } from '@/types/i18n';
+
+interface HeroSectionProps {
+ translations: Translation['hero'];
+ commonTranslations: Translation['common'];
+}
+
+// Composant pour les boutons CTA factorisant la structure répétitive
+interface CTAButtonProps {
+ href: string;
+ primary?: boolean;
+ children: React.ReactNode;
+ icon?: React.ReactNode;
+}
+
+const CTAButton: React.FC = ({ href, primary = false, children, icon }) => {
+ const handleClick = (e: React.MouseEvent) => {
+ e.preventDefault();
+ const targetId = href.replace('#', '');
+ if (targetId === 'services' || targetId === 'about') {
+ document.getElementById(targetId)?.scrollIntoView({
+ behavior: 'smooth',
+ block: 'start'
+ });
+ }
+ };
+
+ const baseClasses = cn(
+ 'inline-flex items-center justify-center',
+ 'text-lg font-bold rounded-2xl',
+ commonClasses.transition,
+ commonClasses.hoverScale,
+ 'active:scale-95'
+ );
+
+ const primaryClasses = cn(
+ 'px-12 py-5 text-white',
+ 'bg-gradient-to-r from-blue-600 to-blue-500',
+ 'shadow-2xl hover:shadow-blue-500/50',
+ 'hover:-translate-y-2 border-2 border-blue-600/20',
+ 'group relative overflow-hidden'
+ );
+
+ const secondaryClasses = cn(
+ 'px-8 py-4 text-blue-700 bg-white',
+ 'border-2 border-blue-600 shadow-lg',
+ 'hover:shadow-xl hover:bg-blue-50'
+ );
+
+ return (
+
+ {primary && (
+
+ )}
+ {children}
+ {icon && {icon} }
+
+ );
+};
+
+export const HeroSection: React.FC = ({ translations, commonTranslations }) => (
+
+ {/* Motifs de fond optimisés - factorisation des styles répétitifs */}
+
+
+
+ {/* Contenu principal */}
+
+
+ {/* Logo principal avec effet moderne */}
+
+
+ {/* Titre principal avec gradient moderne */}
+
+ {translations.title}
+
+
+ {/* Sous-titre avec contraste amélioré */}
+
+ {translations.subtitle}
+
+
+ {/* Call-to-action optimisé */}
+
+ }
+ >
+ {translations.cta}
+
+
+
+ {commonTranslations.learnMore}
+
+
+
+
+);
diff --git a/banquise-website/components/sections/ServicesSection.tsx b/banquise-website/components/sections/ServicesSection.tsx
new file mode 100644
index 0000000..613138c
--- /dev/null
+++ b/banquise-website/components/sections/ServicesSection.tsx
@@ -0,0 +1,47 @@
+import React from 'react';
+import { ServiceCard } from '@/components/common/ServiceCard';
+import { SectionHeader } from '@/components/ui/SectionHeader';
+import { useTranslation } from '@/lib/hooks/useTranslation';
+import type { Service } from '@/types/service';
+
+interface ServicesSectionProps {
+ services: Service[];
+ onServiceClick: (service: Service) => void;
+ translations: {
+ discoverFeatures: string;
+ };
+}
+
+export const ServicesSection: React.FC = ({
+ services,
+ onServiceClick,
+ translations
+}) => {
+ const { t } = useTranslation();
+
+ return (
+
+
+ {/* Header de section moderne avec forte hiérarchie - factorisation */}
+
+
+ {/* Grille de services avec espacement généreux */}
+
+ {services.map((service) => (
+
+ ))}
+
+
+
+ );
+};
diff --git a/banquise-website/components/sections/TechFeaturesSection.tsx b/banquise-website/components/sections/TechFeaturesSection.tsx
new file mode 100644
index 0000000..0762fae
--- /dev/null
+++ b/banquise-website/components/sections/TechFeaturesSection.tsx
@@ -0,0 +1,89 @@
+import React from 'react';
+import { Rocket, Database, Globe, Shield } from 'lucide-react';
+import { useTranslation } from '@/lib/hooks/useTranslation';
+
+export const TechFeaturesSection: React.FC = () => {
+ const { t } = useTranslation();
+
+ return (
+
+ {/* Motif de fond avec grille visible */}
+
+
+ {/* Grille secondaire pour la profondeur */}
+
+
+
+
+
+ {t.infrastructure.title}
+
+
+ {t.infrastructure.subtitle}
+
+
+
+
+
+
+
+
+
+
+
{t.infrastructure.features.performance.title}
+
{t.infrastructure.features.performance.description}
+
+
+
+
+
+
+
+
+
+
+
{t.infrastructure.features.storage.title}
+
{t.infrastructure.features.storage.description}
+
+
+
+
+
+
+
+
+
+
+
{t.infrastructure.features.network.title}
+
{t.infrastructure.features.network.description}
+
+
+
+
+
+
+
+
+
+
+
{t.infrastructure.features.security.title}
+
{t.infrastructure.features.security.description}
+
+
+
+
+
+ );
+};
diff --git a/banquise-website/components/ui/AccordionItem.tsx b/banquise-website/components/ui/AccordionItem.tsx
new file mode 100644
index 0000000..6c67e50
--- /dev/null
+++ b/banquise-website/components/ui/AccordionItem.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import type { AccordionItemProps } from '../../types';
+
+export const AccordionItem: React.FC = ({ title, children, isOpen, onToggle }) => (
+
+ {/* Overlay effect on hover */}
+
+
+
+
+
+);
diff --git a/banquise-website/components/ui/AccordionTitle.tsx b/banquise-website/components/ui/AccordionTitle.tsx
new file mode 100644
index 0000000..9f2dda2
--- /dev/null
+++ b/banquise-website/components/ui/AccordionTitle.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import { LucideIcon } from 'lucide-react';
+import { cn } from '@/lib/utils';
+
+interface AccordionTitleProps {
+ icon: LucideIcon;
+ title: string;
+}
+
+export const AccordionTitle: React.FC = ({ icon: Icon, title }) => (
+
+);
\ No newline at end of file
diff --git a/banquise-website/components/ui/DiscordButton.tsx b/banquise-website/components/ui/DiscordButton.tsx
new file mode 100644
index 0000000..a9ae25a
--- /dev/null
+++ b/banquise-website/components/ui/DiscordButton.tsx
@@ -0,0 +1,47 @@
+import React from 'react';
+import { Button } from '@/components/common/Button';
+import { DiscordLogo } from './DiscordLogo';
+import { URLS } from '@/lib/config/constants';
+
+interface DiscordButtonProps {
+ children: React.ReactNode;
+ href?: string;
+ onClick?: () => void;
+ size?: 'sm' | 'md' | 'lg';
+ className?: string;
+ showIcon?: boolean;
+}
+
+export const DiscordButton: React.FC = ({
+ children,
+ href = URLS.social.discord,
+ onClick,
+ size = 'md',
+ className = '',
+ showIcon = true
+}) => {
+ const content = (
+ <>
+ {showIcon && }
+ {children}
+ >
+ );
+
+ if (href) {
+ return (
+
+
+ {content}
+
+
+ );
+ }
+
+ return (
+
+ {content}
+
+ );
+};
+
+export default DiscordButton;
\ No newline at end of file
diff --git a/banquise-website/components/ui/DiscordLogo.tsx b/banquise-website/components/ui/DiscordLogo.tsx
new file mode 100644
index 0000000..1659fc5
--- /dev/null
+++ b/banquise-website/components/ui/DiscordLogo.tsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import Image from 'next/image';
+
+interface DiscordLogoProps {
+ size?: 'sm' | 'md' | 'lg' | 'xl';
+ variant?: 'svg' | 'png';
+ className?: string;
+ alt?: string;
+}
+
+const sizeClasses = {
+ sm: 'w-4 h-4',
+ md: 'w-6 h-6',
+ lg: 'w-8 h-8',
+ xl: 'w-12 h-12'
+};
+
+// Logo Discord officiel en SVG
+const DiscordSVG: React.FC<{ className?: string }> = ({ className }) => (
+
+
+
+);
+
+export const DiscordLogo: React.FC = ({
+ size = 'md',
+ variant = 'svg',
+ className = '',
+ alt = 'Discord'
+}) => {
+ const baseClasses = sizeClasses[size];
+ const finalClassName = `${baseClasses} ${className}`;
+
+ if (variant === 'png') {
+ return (
+
+ );
+ }
+
+ return ;
+};
+
+// Export du composant SVG pour usage direct
+export const DiscordIcon = () => (
+
+);
+
+export default DiscordLogo;
\ No newline at end of file
diff --git a/banquise-website/components/ui/ModernLanguageSwitcher.tsx b/banquise-website/components/ui/ModernLanguageSwitcher.tsx
new file mode 100644
index 0000000..ec17764
--- /dev/null
+++ b/banquise-website/components/ui/ModernLanguageSwitcher.tsx
@@ -0,0 +1,131 @@
+import React, { useState, useRef, useEffect } from 'react';
+import type { Language } from '@/types/i18n';
+
+// Fonction utilitaire simple pour combiner les classes
+const cn = (...classes: (string | undefined | null | false)[]): string => {
+ return classes.filter(Boolean).join(' ');
+};
+
+interface ModernLanguageSwitcherProps {
+ currentLanguage: Language;
+ onLanguageChange: (language: Language) => void;
+ availableLanguages: Language[];
+}
+
+export const ModernLanguageSwitcher: React.FC = ({
+ currentLanguage,
+ onLanguageChange,
+ availableLanguages
+}) => {
+ const [isOpen, setIsOpen] = useState(false);
+ const containerRef = useRef(null);
+
+ // Gérer les clics à l'extérieur
+ useEffect(() => {
+ const handleClickOutside = (event: MouseEvent) => {
+ if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
+ setIsOpen(false);
+ }
+ };
+
+ const handleEscapeKey = (event: KeyboardEvent) => {
+ if (event.key === 'Escape') {
+ setIsOpen(false);
+ }
+ };
+
+ if (isOpen) {
+ document.addEventListener('mousedown', handleClickOutside);
+ document.addEventListener('keydown', handleEscapeKey);
+
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside);
+ document.removeEventListener('keydown', handleEscapeKey);
+ };
+ }
+ }, [isOpen]);
+
+ const languageConfig: Record = {
+ fr: { name: 'Français', flag: '🇫🇷', nativeName: 'FR' },
+ en: { name: 'English', flag: '🇬🇧', nativeName: 'EN' },
+ };
+
+ const currentConfig = languageConfig[currentLanguage];
+
+ return (
+
+ {/* Trigger Button */}
+
setIsOpen(!isOpen)}
+ className={cn(
+ 'flex items-center space-x-2 px-3 py-2 rounded-lg transition-all duration-200',
+ 'bg-white/10 hover:bg-white/20 border border-white/20 hover:border-white/30',
+ 'text-white text-sm font-medium',
+ 'focus:outline-none focus:ring-2 focus:ring-blue-400/50',
+ 'group'
+ )}
+ aria-expanded={isOpen}
+ aria-haspopup="listbox"
+ >
+ {currentConfig.flag}
+ {currentConfig.nativeName}
+
+ {/* Chevron Icon */}
+
+
+
+
+
+ {/* Dropdown Menu */}
+ {isOpen && (
+
+ {availableLanguages.map((lang) => {
+ const config = languageConfig[lang];
+ const isSelected = lang === currentLanguage;
+
+ return (
+
{
+ onLanguageChange(lang);
+ setIsOpen(false);
+ }}
+ className={cn(
+ 'w-full flex items-center space-x-3 px-4 py-2.5 text-sm transition-all duration-200',
+ 'hover:bg-blue-600/10 focus:bg-blue-600/10',
+ 'focus:outline-none',
+ isSelected
+ ? 'text-blue-800 font-semibold bg-blue-600/10'
+ : 'text-gray-700 hover:text-blue-800'
+ )}
+ role="option"
+ aria-selected={isSelected}
+ >
+ {config.flag}
+ {config.name}
+ {isSelected && (
+
+
+
+ )}
+
+ );
+ })}
+
+ )}
+
+ );
+};
diff --git a/banquise-website/components/ui/OceanBackground.tsx b/banquise-website/components/ui/OceanBackground.tsx
new file mode 100644
index 0000000..048220d
--- /dev/null
+++ b/banquise-website/components/ui/OceanBackground.tsx
@@ -0,0 +1,88 @@
+import React from 'react';
+import { useOceanDepthEffect } from '@/lib/hooks/useOceanDepthEffect';
+
+export const OceanBackground: React.FC = () => {
+ const scrollDepth = useOceanDepthEffect();
+
+ return (
+
+ {/* Couche de base : dégradé océanique naturel de surface vers profondeur */}
+
+
+ {/* Couche d'assombrissement progressif basé sur le scroll */}
+
+
+ {/* Couche de profondeur extrême pour les abysses */}
+
+
+ {/* Rayons de lumière naturels qui s'estompent avec la profondeur */}
+
+
+ {/* Bulles marines qui deviennent plus rares en profondeur */}
+
+ {/* Bulles de surface - nombreuses et actives */}
+
+
+ {/* Bulles de moyenne profondeur - moins nombreuses */}
+
+
+ {/* Bulles des profondeurs - très rares et subtiles */}
+
+
+
+ {/* Effet de caustics (reflets de lumière sous l'eau) qui disparaît en profondeur */}
+
+
+ );
+};
\ No newline at end of file
diff --git a/banquise-website/components/ui/Popup.tsx b/banquise-website/components/ui/Popup.tsx
new file mode 100644
index 0000000..838b795
--- /dev/null
+++ b/banquise-website/components/ui/Popup.tsx
@@ -0,0 +1,149 @@
+import React, { useEffect } from 'react';
+import Image from 'next/image';
+import { URLS } from '@/lib/config/constants';
+import { FeatureBadge, FeatureItem, SectionTitle } from './PopupComponents';
+import { cn, commonClasses } from '@/lib/utils';
+import type { Service } from '@/types/service';
+import type { Translation } from '@/types/i18n';
+import { ClipboardList, Zap, Check, Lock, Rocket } from 'lucide-react';
+
+interface PopupProps {
+ service: Service;
+ onClose: () => void;
+ translations: Translation['common'];
+}
+
+export const Popup: React.FC = ({ service, onClose, translations }) => {
+ // Empêcher le scroll du body quand la popup est ouverte
+ useEffect(() => {
+ const originalStyle = document.body.style.overflow;
+ document.body.style.overflow = 'hidden';
+
+ return () => {
+ document.body.style.overflow = originalStyle || 'unset';
+ };
+ }, []);
+
+ return (
+
+
+
+ {/* Bouton de fermeture fixe au-dessus du contenu */}
+
+
+ ×
+
+
+
+ {/* Contenu avec scroll vertical uniquement */}
+
+ {/* Header */}
+
+
+
+ {service.iconType === 'image' ? (
+
+ ) : service.lucideIcon ? (
+
+ ) : (
+ {service.icon}
+ )}
+
+
+
+ {service.name}
+
+
+ Service d'hébergement professionnel
+
+
+ Haute disponibilité
+ Open Source
+ Communautaire
+
+
+
+
+
+ {/* Content - Forcer le fond blanc */}
+
+ {/* Description */}
+
+
+
+ {service.description}
+
+
+
+
+
+
+
+ {/* Fonctionnalités */}
+
+
+ {service.features.map((feature, index) => (
+
+ ))}
+
+
+ {/* Call to action */}
+
+
+
+
+ {/* Decorative elements */}
+
+
+
+
+ );
+};
diff --git a/banquise-website/components/ui/PopupComponents.tsx b/banquise-website/components/ui/PopupComponents.tsx
new file mode 100644
index 0000000..a8554e1
--- /dev/null
+++ b/banquise-website/components/ui/PopupComponents.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import { LucideIcon } from 'lucide-react';
+import { cn } from '@/lib/utils';
+
+interface FeatureBadgeProps {
+ icon: LucideIcon;
+ title: string;
+ subtitle: string;
+}
+
+export const FeatureBadge: React.FC = ({
+ icon: Icon,
+ title,
+ subtitle
+}) => (
+
+);
+
+interface FeatureItemProps {
+ feature: string;
+ index: number;
+}
+
+export const FeatureItem: React.FC = ({ feature, index }) => (
+
+);
+
+interface SectionTitleProps {
+ icon: LucideIcon;
+ title: string;
+}
+
+export const SectionTitle: React.FC = ({ icon: Icon, title }) => (
+
+
+
+
+ {title}
+
+);
\ No newline at end of file
diff --git a/banquise-website/components/ui/ScrollToTopButton.tsx b/banquise-website/components/ui/ScrollToTopButton.tsx
new file mode 100644
index 0000000..9d7f907
--- /dev/null
+++ b/banquise-website/components/ui/ScrollToTopButton.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import { useScrollEffects } from '@/lib/hooks/useScrollEffects';
+import { useTranslation } from '@/lib/hooks/useTranslation';
+import { ArrowUp } from 'lucide-react';
+
+export const ScrollToTopButton: React.FC = () => {
+ const { isVisible, scrollToTop } = useScrollEffects();
+ const { t } = useTranslation();
+
+ return (
+
+
+
+ {/* Effet de lueur au hover */}
+
+
+ );
+};
diff --git a/banquise-website/components/ui/SectionHeader.tsx b/banquise-website/components/ui/SectionHeader.tsx
new file mode 100644
index 0000000..058c1ef
--- /dev/null
+++ b/banquise-website/components/ui/SectionHeader.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { cn } from '@/lib/utils';
+
+interface SectionHeaderProps {
+ title: string;
+ subtitle?: string;
+ className?: string;
+}
+
+export const SectionHeader: React.FC = ({
+ title,
+ subtitle,
+ className
+}) => (
+
+ {/* Séparateur visuel moderne - factorisation du design répétitif */}
+
+
+ {/* Titre principal avec contraste fort */}
+
+ {title}
+
+
+ {/* Sous-titre avec bon contraste */}
+ {subtitle && (
+
+ {subtitle}
+
+ )}
+
+);
\ No newline at end of file
diff --git a/banquise-website/components/ui/ServiceCardAbout.tsx b/banquise-website/components/ui/ServiceCardAbout.tsx
new file mode 100644
index 0000000..3567f65
--- /dev/null
+++ b/banquise-website/components/ui/ServiceCardAbout.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { LucideIcon } from 'lucide-react';
+import { cn, commonClasses } from '@/lib/utils';
+
+interface ServiceCardAboutProps {
+ icon: LucideIcon;
+ title: string;
+ description: string;
+ colSpan?: boolean;
+}
+
+export const ServiceCardAbout: React.FC = ({
+ icon: Icon,
+ title,
+ description,
+ colSpan = false
+}) => (
+
+
+
+
+
+
{title}
+
{description}
+
+
+);
\ No newline at end of file
diff --git a/banquise-website/eslint.config.js b/banquise-website/eslint.config.js
deleted file mode 100644
index 092408a..0000000
--- a/banquise-website/eslint.config.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import js from '@eslint/js'
-import globals from 'globals'
-import reactHooks from 'eslint-plugin-react-hooks'
-import reactRefresh from 'eslint-plugin-react-refresh'
-import tseslint from 'typescript-eslint'
-
-export default tseslint.config(
- { ignores: ['dist'] },
- {
- extends: [js.configs.recommended, ...tseslint.configs.recommended],
- files: ['**/*.{ts,tsx}'],
- languageOptions: {
- ecmaVersion: 2020,
- globals: globals.browser,
- },
- plugins: {
- 'react-hooks': reactHooks,
- 'react-refresh': reactRefresh,
- },
- rules: {
- ...reactHooks.configs.recommended.rules,
- 'react-refresh/only-export-components': [
- 'warn',
- { allowConstantExport: true },
- ],
- },
- },
-)
diff --git a/banquise-website/index.html b/banquise-website/index.html
deleted file mode 100644
index 2ac6584..0000000
--- a/banquise-website/index.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
- La Banquise - Services d'hébergement
-
-
-
-
-
-
-
-
-
-
diff --git a/banquise-website/src/config/constants.ts b/banquise-website/lib/config/constants.ts
similarity index 60%
rename from banquise-website/src/config/constants.ts
rename to banquise-website/lib/config/constants.ts
index 5a493bf..5ae6a08 100644
--- a/banquise-website/src/config/constants.ts
+++ b/banquise-website/lib/config/constants.ts
@@ -3,10 +3,15 @@ export const URLS = {
wiki: "https://wiki.la-banquise.fr",
gitea: "https://git.la-banquise.fr",
panel: "https://panel.la-banquise.fr",
- auth: "https://auth.la-banquise.fr"
+ auth: "https://auth.la-banquise.fr",
+ pelican: "https://pelican.la-banquise.fr",
+ intra: "https://intra.la-banquise.fr",
+ mails: "https://mails.la-banquise.fr",
+ opencloud: "https://opencloud.la-banquise.fr",
+ ssp: "https://ssp.la-banquise.fr"
},
social: {
- discord: "https://discord.gg/labanquise"
+ discord: "https://discord.gg/bJhM97wans"
},
contact: {
email: "mailto:contact@la-banquise.fr"
diff --git a/banquise-website/lib/data/translations/en.ts b/banquise-website/lib/data/translations/en.ts
new file mode 100644
index 0000000..10eaaed
--- /dev/null
+++ b/banquise-website/lib/data/translations/en.ts
@@ -0,0 +1,276 @@
+import type { Translation } from '@/types/i18n';
+import { URLS } from '@/lib/config/constants';
+import { BookOpen, GitBranch, Gamepad2, KeyRound, Building, Mail } from 'lucide-react';
+
+export const en: Translation = {
+ services: [
+ {
+ name: "Wiki",
+ url: URLS.services.wiki,
+ image: "/assets/wikijs.png",
+ icon: "📚",
+ iconType: "image",
+ description: "Collaborative technical documentation and knowledge sharing platform. Create, edit and organize your guides, tutorials and documentation as a team with integrated versioning system.",
+ features: [
+ "Advanced markdown editor with real-time preview",
+ "Versioning system to track changes",
+ "Real-time collaboration with multiple contributors",
+ "Smart search across all documents",
+ "Predefined templates for different documentation types",
+ "Comment and revision system",
+ "PDF and HTML export for external sharing",
+ "Git integration for backup"
+ ]
+ },
+ {
+ name: "Gitea",
+ url: URLS.services.gitea,
+ image: "/assets/Gitea_Logo.png",
+ icon: "🔧",
+ iconType: "image",
+ description: "Lightweight and performant self-hosted Git service for your development projects. Open-source alternative to GitHub with all essential features for managing your repositories.",
+ features: [
+ "Unlimited public and private Git repositories",
+ "Intuitive web interface for project management",
+ "Issues and pull requests with review system",
+ "Integrated wiki for each project",
+ "CI/CD actions for automation",
+ "Fine-grained permissions and team management",
+ "Complete REST API for integration",
+ "Webhooks for external notifications"
+ ]
+ },
+ {
+ name: "Pelican",
+ url: URLS.services.pelican,
+ image: "/assets/pelican.png",
+ icon: "🐧",
+ iconType: "image",
+ description: "Game server management with dedicated servers (Minecraft, CS2, Palworld, and many others)",
+ features: [
+ "One-click deployment with pre-configured templates",
+ "Real-time administration console",
+ "File management with integrated editor",
+ "Performance and resource monitoring",
+ "Automatic backup system",
+ "Automated task scheduler"
+ ]
+ },
+ {
+ name: "Password Change",
+ url: URLS.services.ssp,
+ image: "/assets/banquise.png",
+ icon: "🔐",
+ iconType: "lucide",
+ lucideIcon: KeyRound,
+ description: "Secure interface for autonomous password management. Easily change your credentials safely.",
+ features: [
+ "Secure interface to change your password",
+ "Password complexity validation",
+ "Email notifications of changes",
+ "Modification history"
+ ]
+ },
+ {
+ name: "OpenCloud",
+ url: URLS.services.opencloud,
+ image: "/assets/opencloud_logo_white.png",
+ icon: "☁️",
+ iconType: "image",
+ description: "Open-source collaborative cloud platform for file storage, sharing and synchronization. Free alternative to Google Drive with full control over your data.",
+ features: [
+ "Secure and encrypted cloud storage",
+ "Multi-device synchronization",
+ "File sharing with secure links",
+ "Collaborative document editing",
+ "Automatic file versioning",
+ "Native mobile applications",
+ "Integration with external tools",
+ "Geo-redundant data backup"
+ ]
+ },
+ {
+ name: "Intranet",
+ url: URLS.services.intra,
+ image: "/assets/banquise.png",
+ icon: "🏢",
+ iconType: "lucide",
+ lucideIcon: Building,
+ description: "Secure private space for the association to centralize internal resources, communications and collaboration tools between members.",
+ features: [
+ "Personalized dashboard for each member",
+ "Event and meeting calendar",
+ "Secure file sharing",
+ "Private discussion forums",
+ "Member directory with profiles",
+ "Internal notification system",
+ "Project and task management",
+ "Archive of decisions and minutes"
+ ]
+ },
+ {
+ name: "Gaming Panel",
+ url: URLS.services.panel,
+ image: "/assets/banquise.png",
+ icon: "🎮",
+ iconType: "lucide",
+ lucideIcon: Gamepad2,
+ description: "Centralized management interface for all your game servers. Easily deploy, configure and monitor your Minecraft, CS2, Garry's Mod and many other servers.",
+ features: [
+ "Support for 20+ popular games (Minecraft, CS2, GMod...)",
+ "One-click deployment with pre-configured templates",
+ "Real-time administration console",
+ "File management with integrated editor",
+ "Performance and resource monitoring",
+ "Automatic backup system",
+ "Automated task scheduler"
+ ]
+ },
+ {
+ name: "Mails",
+ url: URLS.services.mails,
+ image: "/assets/banquise.png",
+ icon: "📧",
+ iconType: "lucide",
+ lucideIcon: Mail,
+ description: "Professional email service with modern web interface. Benefit from a personalized @la-banquise.fr email address with all advanced features.",
+ features: [
+ "Personalized @la-banquise.fr email addresses",
+ "Modern and responsive webmail interface",
+ "Integrated anti-spam and antivirus filters",
+ "Synchronized contacts and calendar",
+ "IMAP/SMTP support for external clients",
+ "Generous storage with archiving",
+ "Communication encryption",
+ "Automatic data backup"
+ ]
+ }
+ ],
+ hero: {
+ title: "Welcome to La Banquise",
+ subtitle: "Hosting provider, for students, by students.",
+ cta: "Discover our services"
+ },
+ navigation: {
+ home: "Home",
+ services: "Services",
+ about: "About",
+ contact: "Contact"
+ },
+ common: {
+ discoverFeatures: "Discover all features",
+ close: "Close",
+ loading: "Loading...",
+ learnMore: "Learn more",
+ backToHome: "Back to home",
+ discoverOffer: "Discover our offer",
+ learnMoreAboutUs: "Learn more about us",
+ sendEmail: "Send us an email",
+ login: "Sign in",
+ joinCommunity: "Join community",
+ backToTop: "Back to top"
+ },
+ user: {
+ profile: "Profile",
+ logout: "Sign out",
+ groups: "Groups",
+ userMenu: "User menu",
+ connecting: "Connecting...",
+ authError: "Authentication error"
+ },
+ sections: {
+ ourServices: "Our Services"
+ },
+ about: {
+ title: "About La Banquise",
+ subtitle: "A passionate community that provides hosting services and collaborative tools for developers and gamers.",
+ faqTitle: "Frequently Asked Questions",
+ mission: {
+ title: "Our Mission",
+ description1: "Train students in deploying and managing infrastructure, and mastering enterprise-grade technologies. This allows us to provide a stable and accessible platform to host your projects, share your knowledge and play together!",
+ description2: "We believe in the power of collaboration and provide modern tools to facilitate teamwork.",
+ tags: {
+ collaboration: "Collaboration",
+ innovation: "Innovation",
+ accessibility: "Accessibility"
+ }
+ },
+ services: {
+ title: "Our Services",
+ wiki: {
+ title: "Wiki",
+ description: "Collaborative documentation and detailed guides"
+ },
+ gitea: {
+ title: "Gitea",
+ description: "Self-hosted Git version control"
+ },
+ panel: {
+ title: "Gaming Panel",
+ description: "Management interface for game servers"
+ },
+ pelican: {
+ title: "Pelican",
+ description: "Static site generator"
+ },
+ intranet: {
+ title: "Intranet",
+ description: "Private association space"
+ },
+ mails: {
+ title: "Webmail",
+ description: "Email messaging service"
+ },
+ opencloud: {
+ title: "OpenCloud",
+ description: "Collaborative cloud platform for all your needs"
+ },
+ note: "All our services are carefully maintained and regularly updated to ensure an optimal experience."
+ },
+ community: {
+ title: "Join the association",
+ description: "Join our Discord server to join the association, chat with us, get help and stay informed about the latest news!",
+ howToJoin: "How to join the association?",
+ steps: {
+ step1: "Create a banquise ticket",
+ step2: "Provide your EPITA login or explain your situation",
+ step3: "A moderator will validate your request and give you access to the association's discord channels!"
+ },
+ joinDiscord: "Join Discord"
+ }
+ },
+ footer: {
+ description: "A passionate community that provides hosting services and collaborative tools for developers and gamers.",
+ ourServices: "Our Services",
+ community: "Community",
+ joinAssociation: "Join the association",
+ joinDescription: "Connect on Discord and create a ticket to join the Banquise community.",
+ joinNow: "Join now",
+ gamingPanel: "Gaming Panel",
+ madeWith: "Made with",
+ by: "by Banquise",
+ copyright: "Community hosting for developers and gamers."
+ },
+ infrastructure: {
+ title: "Our Infrastructure",
+ subtitle: "25+ servers to meet your needs",
+ features: {
+ performance: {
+ title: "High-performance servers",
+ description: "Optimized infrastructure to ensure high performance and maximum availability of your applications"
+ },
+ storage: {
+ title: "Secure storage",
+ description: "Distributed storage solutions with redundancy to guarantee the integrity and durability of your data"
+ },
+ network: {
+ title: "Optimized network",
+ description: "High-availability network architecture with low latency for your critical applications"
+ },
+ security: {
+ title: "Enhanced security",
+ description: "Threat protection with modern security systems and regular updates"
+ }
+ }
+ }
+};
diff --git a/banquise-website/lib/data/translations/fr.ts b/banquise-website/lib/data/translations/fr.ts
new file mode 100644
index 0000000..e874a59
--- /dev/null
+++ b/banquise-website/lib/data/translations/fr.ts
@@ -0,0 +1,276 @@
+import type { Translation } from '@/types/i18n';
+import { URLS } from '@/lib/config/constants';
+import { BookOpen, GitBranch, Gamepad2, KeyRound, Building, Mail } from 'lucide-react';
+
+export const fr: Translation = {
+ services: [
+ {
+ name: "Wiki",
+ url: URLS.services.wiki,
+ image: "/assets/wikijs.png",
+ icon: "📚",
+ iconType: "image",
+ description: "Plateforme collaborative de documentation technique et de partage de connaissances. Créez, modifiez et organisez vos guides, tutoriels et documentations en équipe avec un système de versioning intégré.",
+ features: [
+ "Éditeur markdown avancé avec prévisualisation en temps réel",
+ "Système de versioning pour suivre les modifications",
+ "Collaboration en temps réel avec plusieurs contributeurs",
+ "Recherche intelligente dans tous les documents",
+ "Templates prédéfinis pour différents types de documentation",
+ "Système de commentaires et de révisions",
+ "Export PDF et HTML pour partage externe",
+ "Intégration avec Git pour la sauvegarde"
+ ]
+ },
+ {
+ name: "Gitea",
+ url: URLS.services.gitea,
+ image: "/assets/Gitea_Logo.png",
+ icon: "🔧",
+ iconType: "image",
+ description: "Service Git auto-hébergé lightweight et performant pour vos projets de développement. Alternative open-source à GitHub avec toutes les fonctionnalités essentielles pour gérer vos repositories.",
+ features: [
+ "Repositories Git illimités publics et privés",
+ "Interface web intuitive pour la gestion des projets",
+ "Issues et pull requests avec système de review",
+ "Wiki intégré pour chaque projet",
+ "Actions CI/CD pour l'automatisation",
+ "Gestion fine des permissions et des équipes",
+ "API REST complète pour l'intégration",
+ "Webhooks pour les notifications externes"
+ ]
+ },
+ {
+ name: "Pelican",
+ url: URLS.services.pelican,
+ image: "/assets/pelican.png",
+ icon: "🐧",
+ iconType: "image",
+ description: "Gestion de serveurs de jeux avec serveurs dédiés (Minecraft, CS2, Palworld, et bien d'autres)",
+ features: [
+ "Déploiement en un clic avec templates préconfigurés",
+ "Console d'administration en temps réel",
+ "Gestion des fichiers avec éditeur intégré",
+ "Monitoring des performances et ressources",
+ "Système de sauvegarde automatique",
+ "Planificateur de tâches automatisées"
+ ]
+ },
+ {
+ name: "Changement de mot de passe",
+ url: URLS.services.ssp,
+ image: "/assets/banquise.png",
+ icon: "🔐",
+ iconType: "lucide",
+ lucideIcon: KeyRound,
+ description: "Interface sécurisée pour la gestion autonome de vos mots de passe. Changez facilement vos identifiants en toute sécurité.",
+ features: [
+ "Interface sécurisée pour changer votre mot de passe",
+ "Validation de la complexité des mots de passe",
+ "Notifications par email des changements",
+ "Historique des modifications"
+ ]
+ },
+ {
+ name: "OpenCloud",
+ url: URLS.services.opencloud,
+ image: "/assets/opencloud_logo_white.png",
+ icon: "☁️",
+ iconType: "image",
+ description: "Plateforme cloud collaborative open-source pour le stockage, le partage et la synchronisation de fichiers. Alternative libre à Google Drive avec contrôle total sur vos données.",
+ features: [
+ "Stockage cloud sécurisé et chiffré",
+ "Synchronisation multi-appareils",
+ "Partage de fichiers avec liens sécurisés",
+ "Édition collaborative de documents",
+ "Versioning automatique des fichiers",
+ "Applications mobiles natives",
+ "Intégration avec outils externes",
+ "Sauvegarde géoredondante des données"
+ ]
+ },
+ {
+ name: "Intranet",
+ url: URLS.services.intra,
+ image: "/assets/banquise.png",
+ icon: "🏢",
+ iconType: "lucide",
+ lucideIcon: Building,
+ description: "Espace privé sécurisé de l'association pour centraliser les ressources internes, communications et outils de collaboration entre membres.",
+ features: [
+ "Tableau de bord personnalisé pour chaque membre",
+ "Calendrier des événements et réunions",
+ "Partage de fichiers sécurisé",
+ "Forums de discussion privés",
+ "Annuaire des membres avec profils",
+ "Système de notifications internes",
+ "Gestion des projets et tâches",
+ "Archive des décisions et procès-verbaux"
+ ]
+ },
+ {
+ name: "Panel Gaming",
+ url: URLS.services.panel,
+ image: "/assets/banquise.png",
+ icon: "🎮",
+ iconType: "lucide",
+ lucideIcon: Gamepad2,
+ description: "Interface de gestion centralisée pour tous vos serveurs de jeux. Déployez, configurez et surveillez facilement vos serveurs Minecraft, CS2, Garry's Mod et bien d'autres.",
+ features: [
+ "Support de 20+ jeux populaires (Minecraft, CS2, GMod...)",
+ "Déploiement en un clic avec templates préconfigurés",
+ "Console d'administration en temps réel",
+ "Gestion des fichiers avec éditeur intégré",
+ "Monitoring des performances et ressources",
+ "Système de sauvegarde automatique",
+ "Planificateur de tâches automatisées"
+ ]
+ },
+ {
+ name: "Mails",
+ url: URLS.services.mails,
+ image: "/assets/banquise.png",
+ icon: "📧",
+ iconType: "lucide",
+ lucideIcon: Mail,
+ description: "Service de messagerie électronique professionnel avec interface web moderne. Bénéficiez d'une adresse email personnalisée @la-banquise.fr avec toutes les fonctionnalités avancées.",
+ features: [
+ "Adresses email personnalisées @la-banquise.fr",
+ "Interface webmail moderne et responsive",
+ "Filtres anti-spam et antivirus intégrés",
+ "Contacts et calendrier synchronisés",
+ "Support IMAP/SMTP pour clients externes",
+ "Stockage généreux avec archivage",
+ "Chiffrement des communications",
+ "Sauvegarde automatique des données"
+ ]
+ }
+ ],
+ hero: {
+ title: "Bienvenue chez La Banquise",
+ subtitle: "Hébergeur, pour les étudiants, par des étudiants.",
+ cta: "Découvrir nos services"
+ },
+ navigation: {
+ home: "Accueil",
+ services: "Services",
+ about: "À propos",
+ contact: "Contact"
+ },
+ common: {
+ discoverFeatures: "Découvrir toutes les fonctionnalités",
+ close: "Fermer",
+ loading: "Chargement...",
+ learnMore: "En savoir plus",
+ backToHome: "Retour à l'accueil",
+ discoverOffer: "Découvrir notre offre",
+ learnMoreAboutUs: "En savoir plus sur nous",
+ sendEmail: "Nous envoyer un email",
+ login: "Se connecter",
+ joinCommunity: "Rejoindre la communauté",
+ backToTop: "Retour en haut de page"
+ },
+ user: {
+ profile: "Profil",
+ logout: "Se déconnecter",
+ groups: "Groupes",
+ userMenu: "Menu utilisateur",
+ connecting: "Connexion en cours...",
+ authError: "Erreur d'authentification"
+ },
+ sections: {
+ ourServices: "Nos Services"
+ },
+ about: {
+ title: "À Propos de La Banquise",
+ subtitle: "Une communauté passionnée qui propose des services d'hébergement et des outils collaboratifs pour les développeurs et les gamers.",
+ faqTitle: "Questions Fréquentes",
+ mission: {
+ title: "Notre Mission",
+ description1: "Former les étudiants au déploiement et à la gestion d'une infrastructure, et de maîtriser des technologies entreprise grade. Cela permet de fournir une plateforme stable et accessible pour héberger vos projets, partager vos connaissances et jouer ensemble !",
+ description2: "Nous croyons en la puissance de la collaboration et mettons à disposition des outils modernes pour faciliter le travail en équipe.",
+ tags: {
+ collaboration: "Collaboration",
+ innovation: "Innovation",
+ accessibility: "Accessibilité"
+ }
+ },
+ services: {
+ title: "Nos Services",
+ wiki: {
+ title: "Wiki",
+ description: "Documentation collaborative et guides détaillés"
+ },
+ gitea: {
+ title: "Gitea",
+ description: "Gestion de versions Git auto-hébergée"
+ },
+ panel: {
+ title: "Panel de Jeux",
+ description: "Interface de gestion pour serveurs de jeux"
+ },
+ pelican: {
+ title: "Pelican",
+ description: "Générateur de sites statiques"
+ },
+ intranet: {
+ title: "Intranet",
+ description: "Espace privé de l'association"
+ },
+ mails: {
+ title: "Webmail",
+ description: "Service de messagerie électronique"
+ },
+ opencloud: {
+ title: "OpenCloud",
+ description: "Plateforme cloud collaborative pour tous vos besoins"
+ },
+ note: "Tous nos services sont maintenus avec soin et régulièrement mis à jour pour garantir une expérience optimale."
+ },
+ community: {
+ title: "Rejoindre l'association",
+ description: "Rejoignez notre serveur Discord pour rejoindre l'asso, échanger avec nous, obtenir de l'aide et rester informé des dernières nouveautés !",
+ howToJoin: "Comment rejoindre l'asso ?",
+ steps: {
+ step1: "Créez un ticket banquise",
+ step2: "Donnez votre login EPITA ou expliquez votre situation",
+ step3: "Un modérateur validera votre demande et vous donnera accès aux salons discord de l'asso !"
+ },
+ joinDiscord: "Rejoindre Discord"
+ }
+ },
+ footer: {
+ description: "Une communauté passionnée qui propose des services d'hébergement et des outils collaboratifs pour les développeurs et les gamers.",
+ ourServices: "Nos Services",
+ community: "Communauté",
+ joinAssociation: "Rejoindre l'asso",
+ joinDescription: "Connectez-vous sur Discord et créez un ticket pour rejoindre la communauté Banquise.",
+ joinNow: "Rejoindre maintenant",
+ gamingPanel: "Panel de Jeux",
+ madeWith: "Fait avec",
+ by: "par Banquise",
+ copyright: "Hébergement communautaire pour développeurs et gamers."
+ },
+ infrastructure: {
+ title: "Notre Infrastructure",
+ subtitle: "25+ serveurs pour répondre à vos besoins",
+ features: {
+ performance: {
+ title: "Serveurs performants",
+ description: "Infrastructure optimisée pour assurer des performances élevées et une disponibilité maximale de vos applications"
+ },
+ storage: {
+ title: "Stockage sécurisé",
+ description: "Solutions de stockage distribuées avec redondance pour garantir l'intégrité et la durabilité de vos données"
+ },
+ network: {
+ title: "Réseau optimisé",
+ description: "Architecture réseau à haute disponibilité avec une faible latence pour vos applications critiques"
+ },
+ security: {
+ title: "Sécurité renforcée",
+ description: "Protection contre les menaces avec systèmes de sécurité modernes et mises à jour régulières"
+ }
+ }
+ }
+};
diff --git a/banquise-website/lib/data/translations/index.ts b/banquise-website/lib/data/translations/index.ts
new file mode 100644
index 0000000..5ceb422
--- /dev/null
+++ b/banquise-website/lib/data/translations/index.ts
@@ -0,0 +1,14 @@
+import { fr } from './fr';
+import { en } from './en';
+import type { Language, Translation } from '@/types/i18n';
+
+export const translations: Record = {
+ fr,
+ en,
+ // Ajoutez d'autres langues ici :
+ // es,
+ // de,
+};
+
+export const defaultLanguage: Language = 'fr';
+export const availableLanguages: Language[] = ['fr', 'en'];
diff --git a/banquise-website/lib/hooks/useAccordion.ts b/banquise-website/lib/hooks/useAccordion.ts
new file mode 100644
index 0000000..f2ff773
--- /dev/null
+++ b/banquise-website/lib/hooks/useAccordion.ts
@@ -0,0 +1,33 @@
+import { useState, useCallback } from 'react';
+
+/**
+ * Hook personnalisé pour gérer l'état des accordéons
+ * Optimisé avec des callbacks memoized et une API simplifiée
+ */
+export const useAccordion = (initialState: string | null = null) => {
+ const [openAccordion, setOpenAccordion] = useState(initialState);
+
+ const toggleAccordion = useCallback((title: string) => {
+ setOpenAccordion(prev => prev === title ? null : title);
+ }, []);
+
+ const openSpecificAccordion = useCallback((title: string) => {
+ setOpenAccordion(title);
+ }, []);
+
+ const closeAccordion = useCallback(() => {
+ setOpenAccordion(null);
+ }, []);
+
+ const isOpen = useCallback((title: string) => {
+ return openAccordion === title;
+ }, [openAccordion]);
+
+ return {
+ openAccordion,
+ toggleAccordion,
+ openSpecificAccordion,
+ closeAccordion,
+ isOpen,
+ };
+};
diff --git a/banquise-website/lib/hooks/useAuth.ts b/banquise-website/lib/hooks/useAuth.ts
new file mode 100644
index 0000000..08f5f19
--- /dev/null
+++ b/banquise-website/lib/hooks/useAuth.ts
@@ -0,0 +1,55 @@
+import { useState, useEffect } from 'react';
+import { authService, type AuthStatus } from '@/lib/services/auth';
+
+export const useAuth = () => {
+ const [authStatus, setAuthStatus] = useState({
+ isAuthenticated: false,
+ });
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ const checkAuth = async () => {
+ try {
+ setIsLoading(true);
+ setError(null);
+ const status = await authService.checkAuthStatus();
+ setAuthStatus(status);
+ } catch (err) {
+ setError('Erreur lors de la vérification de l\'authentification');
+ console.error('Auth check error:', err);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ checkAuth();
+ }, []);
+
+ const login = () => {
+ authService.login();
+ };
+
+ const logout = async () => {
+ try {
+ await authService.logout();
+ setAuthStatus({ isAuthenticated: false });
+ } catch (err) {
+ setError('Erreur lors de la déconnexion');
+ console.error('Logout error:', err);
+ }
+ };
+
+ const refreshAuth = () => {
+ checkAuth();
+ };
+
+ return {
+ ...authStatus,
+ isLoading,
+ error,
+ login,
+ logout,
+ refreshAuth,
+ };
+};
\ No newline at end of file
diff --git a/banquise-website/lib/hooks/useCommon.ts b/banquise-website/lib/hooks/useCommon.ts
new file mode 100644
index 0000000..92f82ac
--- /dev/null
+++ b/banquise-website/lib/hooks/useCommon.ts
@@ -0,0 +1,118 @@
+import { useEffect, useCallback, useState } from 'react';
+
+/**
+ * Hook centralisé pour la gestion du scroll du body
+ * Factorisation de la logique répétée dans plusieurs composants
+ */
+export const useBodyScrollLock = (isLocked: boolean) => {
+ useEffect(() => {
+ const originalStyle = document.body.style.overflow;
+
+ if (isLocked) {
+ document.body.style.overflow = 'hidden';
+ } else {
+ document.body.style.overflow = originalStyle || 'unset';
+ }
+
+ return () => {
+ document.body.style.overflow = originalStyle || 'unset';
+ };
+ }, [isLocked]);
+};
+
+/**
+ * Hook pour gérer les événements de redimensionnement avec debounce
+ */
+export const useResizeEvent = (callback: () => void, breakpoint: number = 768, delay: number = 100) => {
+ useEffect(() => {
+ let timeoutId: NodeJS.Timeout;
+
+ const handleResize = () => {
+ clearTimeout(timeoutId);
+ timeoutId = setTimeout(() => {
+ if (window.innerWidth >= breakpoint) {
+ callback();
+ }
+ }, delay);
+ };
+
+ window.addEventListener('resize', handleResize);
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ clearTimeout(timeoutId);
+ };
+ }, [callback, breakpoint, delay]);
+};
+
+/**
+ * Hook pour les états de toggle simples (booléens)
+ */
+export const useToggle = (initialState: boolean = false) => {
+ const [state, setState] = useState(initialState);
+
+ const toggle = useCallback(() => setState(prev => !prev), []);
+ const setTrue = useCallback(() => setState(true), []);
+ const setFalse = useCallback(() => setState(false), []);
+
+ return {
+ state,
+ toggle,
+ setTrue,
+ setFalse,
+ setState
+ };
+};
+
+/**
+ * Hook pour gérer les modales génériques
+ */
+export const useModal = (initialState: T | null = null) => {
+ const [data, setData] = useState(initialState);
+
+ const open = useCallback((newData: T) => {
+ setData(newData);
+ }, []);
+
+ const close = useCallback(() => {
+ setData(null);
+ }, []);
+
+ const isOpen = data !== null;
+
+ return {
+ data,
+ open,
+ close,
+ isOpen
+ };
+};
+
+/**
+ * Hook pour la navigation entre sections avec scroll smooth
+ */
+export const useNavigation = () => {
+ const scrollToSection = useCallback((sectionId: string) => {
+ if (sectionId === 'home') {
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+ } else if (sectionId === 'contact') {
+ window.location.href = 'mailto:contact@la-banquise.fr';
+ } else {
+ const element = document.getElementById(sectionId);
+ if (element) {
+ element.scrollIntoView({ behavior: 'smooth', block: 'start' });
+ }
+ }
+ }, []);
+
+ const createNavHandler = useCallback((onClose?: () => void) => {
+ return (sectionId: string) => {
+ scrollToSection(sectionId);
+ onClose?.();
+ };
+ }, [scrollToSection]);
+
+ return {
+ scrollToSection,
+ createNavHandler
+ };
+};
\ No newline at end of file
diff --git a/banquise-website/lib/hooks/useOceanDepthEffect.ts b/banquise-website/lib/hooks/useOceanDepthEffect.ts
new file mode 100644
index 0000000..d837806
--- /dev/null
+++ b/banquise-website/lib/hooks/useOceanDepthEffect.ts
@@ -0,0 +1,35 @@
+import { useState, useEffect } from 'react';
+
+export const useOceanDepthEffect = () => {
+ const [scrollDepth, setScrollDepth] = useState(0);
+
+ useEffect(() => {
+ const handleScroll = () => {
+ const scrollPosition = window.scrollY;
+ const documentHeight = document.documentElement.scrollHeight - window.innerHeight;
+
+ if (documentHeight <= 0) {
+ setScrollDepth(0);
+ return;
+ }
+
+ // Calcul de la profondeur avec courbe d'accélération naturelle
+ const rawPercentage = Math.min(scrollPosition / documentHeight, 1);
+
+ // Courbe d'easing pour un effet plus naturel de descente océanique
+ // Plus on descend, plus l'assombrissement s'accélère (comme dans l'océan réel)
+ const easedDepth = rawPercentage < 0.5
+ ? 2 * rawPercentage * rawPercentage
+ : 1 - Math.pow(-2 * rawPercentage + 2, 3) / 2;
+
+ setScrollDepth(Math.min(easedDepth, 1));
+ };
+
+ window.addEventListener('scroll', handleScroll, { passive: true });
+ handleScroll(); // Initial call
+
+ return () => window.removeEventListener('scroll', handleScroll);
+ }, []);
+
+ return scrollDepth;
+};
diff --git a/banquise-website/lib/hooks/useScrollEffects.ts b/banquise-website/lib/hooks/useScrollEffects.ts
new file mode 100644
index 0000000..8b55137
--- /dev/null
+++ b/banquise-website/lib/hooks/useScrollEffects.ts
@@ -0,0 +1,49 @@
+import { useState, useEffect, useCallback } from 'react';
+
+/**
+ * Hook personnalisé pour gérer les effets de scroll
+ * Remplace la logique répétée dans Navigation.tsx et ScrollToTopButton.tsx
+ */
+export const useScrollEffects = () => {
+ const [scrolled, setScrolled] = useState(false);
+ const [isVisible, setIsVisible] = useState(false);
+
+ useEffect(() => {
+ const handleScroll = () => {
+ const scrollY = window.scrollY;
+ setScrolled(scrollY > 20);
+ setIsVisible(scrollY > 300);
+ };
+
+ window.addEventListener('scroll', handleScroll, { passive: true });
+
+ // Call once to set initial state
+ handleScroll();
+
+ return () => window.removeEventListener('scroll', handleScroll);
+ }, []);
+
+ const scrollToTop = useCallback(() => {
+ window.scrollTo({
+ top: 0,
+ behavior: 'smooth'
+ });
+ }, []);
+
+ const scrollToElement = useCallback((elementId: string) => {
+ const element = document.getElementById(elementId);
+ if (element) {
+ element.scrollIntoView({
+ behavior: 'smooth',
+ block: 'start'
+ });
+ }
+ }, []);
+
+ return {
+ scrolled,
+ isVisible,
+ scrollToTop,
+ scrollToElement,
+ };
+};
diff --git a/banquise-website/lib/hooks/useServiceModal.ts b/banquise-website/lib/hooks/useServiceModal.ts
new file mode 100644
index 0000000..f348f4b
--- /dev/null
+++ b/banquise-website/lib/hooks/useServiceModal.ts
@@ -0,0 +1,27 @@
+import { useState, useCallback } from 'react';
+import type { Service } from '@/types/service';
+
+/**
+ * Hook personnalisé pour gérer l'état des modales de services
+ * Remplace la logique dans App.tsx et simplifie la gestion d'état
+ */
+export const useServiceModal = () => {
+ const [selectedService, setSelectedService] = useState(null);
+
+ const openServiceModal = useCallback((service: Service) => {
+ setSelectedService(service);
+ }, []);
+
+ const closeServiceModal = useCallback(() => {
+ setSelectedService(null);
+ }, []);
+
+ const isModalOpen = selectedService !== null;
+
+ return {
+ selectedService,
+ openServiceModal,
+ closeServiceModal,
+ isModalOpen,
+ };
+};
diff --git a/banquise-website/lib/hooks/useTranslation.tsx b/banquise-website/lib/hooks/useTranslation.tsx
new file mode 100644
index 0000000..33211d4
--- /dev/null
+++ b/banquise-website/lib/hooks/useTranslation.tsx
@@ -0,0 +1,50 @@
+import { useState, useEffect, useMemo } from 'react';
+import type { Language, Translation } from '@/types/i18n';
+import { translations, defaultLanguage } from '@/lib/data/translations';
+
+export const useTranslation = () => {
+ // Initialize on server with default language to avoid using localStorage during SSR
+ const [currentLanguage, setCurrentLanguage] = useState(defaultLanguage);
+
+ // On client, read saved language from localStorage
+ useEffect(() => {
+ try {
+ const saved = (typeof window !== 'undefined' && localStorage.getItem('language')) as Language | null;
+ if (saved && translations[saved]) {
+ setCurrentLanguage(saved);
+ }
+ } catch (e) {
+ // ignore (e.g., localStorage not available)
+ }
+ }, []);
+
+ // Persist language changes on client
+ useEffect(() => {
+ try {
+ if (typeof window !== 'undefined') {
+ localStorage.setItem('language', currentLanguage);
+ }
+ } catch (e) {
+ // ignore
+ }
+ }, [currentLanguage]);
+
+ // Memoize the translation object to prevent unnecessary re-renders
+ const t = useMemo(() => translations[currentLanguage], [currentLanguage]);
+
+ // Memoize available languages array
+ const availableLanguages = useMemo(() => Object.keys(translations) as Language[], []);
+
+ const changeLanguage = (language: Language) => {
+ if (translations[language]) {
+ setCurrentLanguage(language);
+ }
+ };
+
+ return {
+ t,
+ currentLanguage,
+ changeLanguage,
+ availableLanguages,
+ };
+};
diff --git a/banquise-website/lib/services/auth.ts b/banquise-website/lib/services/auth.ts
new file mode 100644
index 0000000..0feb55b
--- /dev/null
+++ b/banquise-website/lib/services/auth.ts
@@ -0,0 +1,57 @@
+import { URLS } from '@/lib/config/constants';
+
+export interface AutheliaUser {
+ name: string;
+ email: string;
+ groups: string[];
+ avatar?: string;
+}
+
+export interface AuthStatus {
+ isAuthenticated: boolean;
+ user?: AutheliaUser;
+}
+
+class AuthService {
+ // Keep the constant in case other code expects it, but we no longer call it
+ private authBaseUrl = URLS?.services?.auth ?? '';
+
+ /**
+ * Authelia integration intentionally disabled.
+ * Return unauthenticated status to remove external links while preserving API.
+ */
+ async checkAuthStatus(): Promise {
+ return { isAuthenticated: false };
+ }
+
+ /**
+ * No user info available when Authelia is disabled.
+ */
+ async getUserInfo(): Promise {
+ return undefined;
+ }
+
+ private generateAvatarUrl(_identifier: string): string {
+ return '';
+ }
+
+ private simpleHash(_str: string): string {
+ return '';
+ }
+
+ /**
+ * Disabled: do nothing instead of redirecting to an external auth provider.
+ */
+ login(): void {
+ return;
+ }
+
+ /**
+ * Disabled: no-op logout.
+ */
+ async logout(): Promise {
+ return;
+ }
+}
+
+export const authService = new AuthService();
\ No newline at end of file
diff --git a/banquise-website/lib/styles/designSystem.ts b/banquise-website/lib/styles/designSystem.ts
new file mode 100644
index 0000000..246efe4
--- /dev/null
+++ b/banquise-website/lib/styles/designSystem.ts
@@ -0,0 +1,197 @@
+// Design System La Banquise - Système centralisé de styles
+export const designSystem = {
+ // 🎨 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-[#5865F2] to-[#7289DA]", // Couleurs officielles Discord
+ discordHover: "hover:from-[#4752C4] hover:to-[#5B6EAE]", // Couleurs Discord hover officielles
+ hero: "bg-gradient-to-br from-banquise-blue to-banquise-blue-dark",
+ section: "bg-gradient-to-b from-white/95 to-white"
+ },
+
+ // 🎯 Boutons optimisés
+ buttons: {
+ base: "inline-flex items-center justify-center font-bold border-0 rounded-2xl transition-all duration-300 active:scale-95",
+ effects: "hover:shadow-xl hover:-translate-y-1 hover:scale-105",
+ variants: {
+ primary: "text-white",
+ discord: "group relative overflow-hidden text-white font-semibold rounded-xl hover:shadow-[#5865F2]/25", // Ombre officielle Discord
+ auth: "group relative overflow-hidden text-white font-semibold rounded-xl",
+ secondary: "bg-white/10 backdrop-blur-sm text-white border border-white/20",
+ outline: "bg-transparent border-2 border-banquise-blue text-banquise-blue hover:bg-banquise-blue hover:text-white"
+ },
+ sizes: {
+ sm: "px-3 py-2 text-sm",
+ md: "px-4 lg:px-6 py-2.5 lg:py-3 text-sm lg:text-base",
+ lg: "px-6 lg:px-8 py-3 lg:py-4 text-base lg:text-lg"
+ }
+ },
+
+ // 🃏 Cartes
+ cards: {
+ base: "backdrop-blur-lg rounded-2xl border transition-all duration-300",
+ borders: {
+ default: "border-banquise-blue-lightest/30",
+ hover: "hover:border-banquise-blue-lightest/50",
+ active: "border-banquise-blue/50"
+ },
+ effects: {
+ hover: "hover:shadow-xl",
+ lift: "hover:-translate-y-4 hover:shadow-2xl",
+ interactive: "cursor-pointer hover:-translate-y-4 hover:shadow-2xl active:scale-95"
+ },
+ backgrounds: {
+ glass: "bg-white/80 backdrop-blur-lg",
+ gradient: "bg-gradient-to-br from-white/90 to-white/80",
+ solid: "bg-white"
+ }
+ },
+
+ // 📝 Typographie
+ typography: {
+ headings: {
+ xl: "text-3xl sm:text-4xl md:text-5xl font-heading font-bold tracking-tight",
+ lg: "text-2xl sm:text-3xl md:text-4xl font-heading font-bold tracking-tight",
+ md: "text-xl sm:text-2xl md:text-3xl font-heading font-bold tracking-tight",
+ sm: "text-lg sm:text-xl md:text-2xl font-heading font-semibold tracking-tight"
+ },
+ body: {
+ xl: "text-lg sm:text-xl md:text-2xl leading-relaxed",
+ lg: "text-base sm:text-lg md:text-xl leading-relaxed",
+ md: "text-sm sm:text-base md:text-lg leading-relaxed",
+ sm: "text-xs sm:text-sm md:text-base leading-relaxed"
+ },
+ colors: {
+ primary: "text-banquise-gray",
+ secondary: "text-banquise-blue-dark",
+ muted: "text-banquise-gray/80",
+ light: "text-banquise-blue-lightest",
+ white: "text-white/90"
+ },
+ weights: {
+ normal: "font-normal",
+ medium: "font-medium",
+ semibold: "font-semibold",
+ bold: "font-bold"
+ }
+ },
+
+ // 📐 Layout
+ layout: {
+ sections: {
+ default: "py-12 sm:py-16 md:py-20",
+ compact: "py-8 sm:py-12 md:py-16",
+ spacious: "py-16 sm:py-20 md:py-24"
+ },
+ containers: {
+ default: "w-full max-w-6xl mx-auto px-4 sm:px-6 md:px-8",
+ narrow: "w-full max-w-4xl mx-auto px-4 sm:px-6 md:px-8",
+ wide: "w-full max-w-7xl mx-auto px-4 sm:px-6 md:px-8"
+ },
+ dividers: {
+ default: "w-20 h-1 bg-gradient-to-r from-banquise-blue-lightest to-banquise-blue mx-auto rounded-full",
+ small: "w-12 h-1 bg-gradient-to-r from-banquise-blue-lightest to-banquise-blue mx-auto rounded-full",
+ large: "w-32 h-1 bg-gradient-to-r from-banquise-blue-lightest to-banquise-blue mx-auto rounded-full"
+ },
+ grids: {
+ responsive: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-8",
+ auto: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 sm:gap-6",
+ services: "grid grid-cols-1 lg:grid-cols-2 gap-6 lg:gap-8"
+ }
+ },
+
+ // 🎯 Icônes
+ icons: {
+ sizes: {
+ xs: "w-4 h-4",
+ sm: "w-6 h-6",
+ md: "w-8 h-8",
+ lg: "w-12 h-12",
+ xl: "w-16 h-16 sm:w-20 sm:h-20 lg:w-24 lg:h-24"
+ },
+ containers: {
+ card: "rounded-2xl flex items-center justify-center shadow-lg",
+ small: "w-10 h-10 rounded-lg flex items-center justify-center text-white",
+ service: "text-3xl sm:text-4xl lg:text-5xl"
+ },
+ effects: {
+ hover: "transition-transform duration-300 hover:scale-110",
+ spin: "animate-spin",
+ bounce: "animate-bounce"
+ }
+ },
+
+ // 🧭 Navigation
+ navigation: {
+ links: {
+ desktop: "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",
+ mobile: "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"
+ },
+ effects: {
+ underline: "after:absolute after:bottom-1 after:left-1/2 after:w-0 after:h-0.5 after:bg-banquise-blue-lightest after:transition-all after:duration-300 group-hover:after:w-3/4 group-hover:after:left-1/8",
+ glow: "hover:drop-shadow-lg hover:drop-shadow-banquise-blue-lightest/50"
+ }
+ },
+
+ // ⚡ Animations & Transitions
+ animations: {
+ transitions: {
+ fast: "transition-all duration-200",
+ default: "transition-all duration-300",
+ slow: "transition-all duration-500"
+ },
+ transforms: {
+ lift: "hover:-translate-y-1",
+ liftLarge: "hover:-translate-y-4",
+ scale: "hover:scale-105",
+ scaleSmall: "hover:scale-102"
+ },
+ loading: {
+ spin: "animate-spin",
+ pulse: "animate-pulse",
+ bounce: "animate-bounce"
+ }
+ },
+
+ // 🌊 Effets spéciaux La Banquise
+ effects: {
+ ocean: {
+ wave: "animate-pulse",
+ depth: "backdrop-blur-xl",
+ surface: "bg-gradient-to-b from-transparent to-banquise-blue/5"
+ },
+ ice: {
+ crystal: "backdrop-blur-lg bg-white/10",
+ frost: "backdrop-blur-sm bg-white/5",
+ shine: "bg-gradient-to-br from-white/20 to-transparent"
+ }
+ }
+} as const;
+
+// 🎨 Utilitaires de combinaison
+export const combineStyles = {
+ // Bouton primaire complet
+ primaryButton: `${designSystem.buttons.base} ${designSystem.buttons.effects} ${designSystem.gradients.primary} ${designSystem.buttons.variants.primary}`,
+
+ // Carte interactive complète
+ interactiveCard: `${designSystem.cards.base} ${designSystem.cards.borders.default} ${designSystem.cards.effects.interactive} ${designSystem.cards.backgrounds.glass}`,
+
+ // Section standard
+ standardSection: `${designSystem.layout.sections.default} ${designSystem.layout.containers.default}`,
+
+ // Titre de section
+ sectionTitle: `${designSystem.typography.headings.lg} ${designSystem.typography.colors.primary}`,
+
+ // Lien de navigation desktop
+ navLink: `${designSystem.navigation.links.desktop} ${designSystem.navigation.effects.underline}`,
+
+ // Grid responsive services
+ servicesGrid: designSystem.layout.grids.services
+} as const;
+
+// Type pour l'autocomplétion
+export type DesignSystemKey = keyof typeof designSystem;
+export type CombinedStyleKey = keyof typeof combineStyles;
\ No newline at end of file
diff --git a/banquise-website/lib/utils/index.ts b/banquise-website/lib/utils/index.ts
new file mode 100644
index 0000000..a2d49b0
--- /dev/null
+++ b/banquise-website/lib/utils/index.ts
@@ -0,0 +1,79 @@
+// Utilitaires centralisés pour éviter la duplication
+
+/**
+ * Combine les classes CSS en filtrant les valeurs falsy
+ * Remplace les fonctions mergeClasses et cn dupliquées
+ */
+export const cn = (...classes: (string | undefined | null | false)[]): string => {
+ return classes.filter(Boolean).join(' ');
+};
+
+/**
+ * Hook personnalisé pour gérer le scroll du body
+ * Factorisation de la logique répétée dans plusieurs composants
+ */
+export const useBodyScrollLock = (isLocked: boolean) => {
+ const originalStyle = document.body.style.overflow;
+
+ if (isLocked) {
+ document.body.style.overflow = 'hidden';
+ } else {
+ document.body.style.overflow = originalStyle || 'unset';
+ }
+
+ // Cleanup function
+ return () => {
+ document.body.style.overflow = originalStyle || 'unset';
+ };
+};
+
+/**
+ * Configuration de navigation centralisée
+ */
+export const createNavClickHandler = (onClose?: () => void) => {
+ return (sectionId: string) => {
+ if (sectionId === 'home') {
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+ } else if (sectionId === 'contact') {
+ window.location.href = 'mailto:contact@la-banquise.fr';
+ } else {
+ const element = document.getElementById(sectionId);
+ if (element) {
+ element.scrollIntoView({ behavior: 'smooth', block: 'start' });
+ }
+ }
+ onClose?.();
+ };
+};
+
+/**
+ * Gestionnaire d'événements de redimensionnement optimisé
+ */
+export const useResizeHandler = (callback: () => void, breakpoint: number = 768) => {
+ const handleResize = () => {
+ if (window.innerWidth >= breakpoint) {
+ callback();
+ }
+ };
+
+ window.addEventListener('resize', handleResize);
+ return () => window.removeEventListener('resize', handleResize);
+};
+
+/**
+ * Classes CSS communes pour éviter la répétition
+ */
+export const commonClasses = {
+ // Transitions
+ transition: 'transition-all duration-200 ease-in-out',
+
+ // Hover effects communs
+ hoverScale: 'hover:scale-105 active:scale-95',
+ cardHover: 'hover:shadow-xl hover:-translate-y-1',
+
+ // Boutons communs
+ buttonBase: 'inline-flex items-center justify-center font-semibold rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-blue-400/50',
+
+ // Navigation
+ navLink: 'px-4 py-2 text-white/90 hover:text-white font-medium rounded-lg transition-colors duration-200 hover:bg-white/10',
+} as const;
\ No newline at end of file
diff --git a/banquise-website/next-env.d.ts b/banquise-website/next-env.d.ts
new file mode 100644
index 0000000..830fb59
--- /dev/null
+++ b/banquise-website/next-env.d.ts
@@ -0,0 +1,6 @@
+///
+///
+///
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/banquise-website/package.json b/banquise-website/package.json
index 5bbfe07..225dcd9 100644
--- a/banquise-website/package.json
+++ b/banquise-website/package.json
@@ -4,41 +4,29 @@
"version": "0.0.0",
"type": "module",
"scripts": {
- "dev": "vite",
- "build": "tsc -b && vite build",
- "lint": "eslint .",
- "preview": "vite preview"
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start -p $PORT",
+ "lint": "next lint"
},
"dependencies": {
- "axios": "^1.6.5",
- "clsx": "^2.1.0",
- "framer-motion": "^10.18.0",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "react-icons": "^4.12.0",
- "react-router-dom": "^6.22.0",
- "@tanstack/react-query": "^5.17.9",
- "tailwind-merge": "^2.2.0",
- "zustand": "^4.4.7"
+ "lucide-react": "^0.544.0",
+ "next": "^15.5.3",
+ "react": "^19.1.1",
+ "react-dom": "^19.1.1"
},
"devDependencies": {
- "@eslint/js": "^9.25.0",
- "@tailwindcss/forms": "^0.5.7",
- "@tailwindcss/typography": "^0.5.10",
- "@types/react": "^18.2.58",
- "@types/react-dom": "^18.2.19",
- "@vitejs/plugin-react": "^4.4.1",
- "autoprefixer": "^10.4.16",
- "eslint": "^9.25.0",
- "eslint-plugin-react-hooks": "^5.2.0",
- "eslint-plugin-react-refresh": "^0.4.19",
- "eslint-plugin-tailwindcss": "^3.14.0",
- "globals": "^16.0.0",
- "postcss": "^8.4.33",
- "typescript": "~5.8.3",
- "typescript-eslint": "^8.30.1",
- "vite": "^6.3.5",
- "vite-plugin-compression": "^0.5.1",
- "tailwindcss": "^3.4.1"
+ "@tailwindcss/forms": "^0.5.10",
+ "@tailwindcss/postcss": "^4.1.13",
+ "@tailwindcss/typography": "^0.5.16",
+ "@types/node": "24.3.3",
+ "@types/react": "^19.1.13",
+ "@types/react-dom": "^19.1.9",
+ "autoprefixer": "^10.4.21",
+ "eslint": "^9.35.0",
+ "eslint-config-next": "^15.5.3",
+ "postcss": "^8.5.6",
+ "tailwindcss": "^4.1.13",
+ "typescript": "~5.9.2"
}
}
diff --git a/banquise-website/pnpm-lock.yaml b/banquise-website/pnpm-lock.yaml
new file mode 100644
index 0000000..d50f1ef
--- /dev/null
+++ b/banquise-website/pnpm-lock.yaml
@@ -0,0 +1,3928 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ lucide-react:
+ specifier: ^0.544.0
+ version: 0.544.0(react@19.1.1)
+ next:
+ specifier: ^15.5.3
+ version: 15.5.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ react:
+ specifier: ^19.1.1
+ version: 19.1.1
+ react-dom:
+ specifier: ^19.1.1
+ version: 19.1.1(react@19.1.1)
+ devDependencies:
+ '@tailwindcss/forms':
+ specifier: ^0.5.10
+ version: 0.5.10(tailwindcss@4.1.13)
+ '@tailwindcss/postcss':
+ specifier: ^4.1.13
+ version: 4.1.13
+ '@tailwindcss/typography':
+ specifier: ^0.5.16
+ version: 0.5.16(tailwindcss@4.1.13)
+ '@types/node':
+ specifier: 24.3.3
+ version: 24.3.3
+ '@types/react':
+ specifier: ^19.1.13
+ version: 19.1.13
+ '@types/react-dom':
+ specifier: ^19.1.9
+ version: 19.1.9(@types/react@19.1.13)
+ autoprefixer:
+ specifier: ^10.4.21
+ version: 10.4.21(postcss@8.5.6)
+ eslint:
+ specifier: ^9.35.0
+ version: 9.35.0(jiti@2.5.1)
+ eslint-config-next:
+ specifier: ^15.5.3
+ version: 15.5.3(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)
+ postcss:
+ specifier: ^8.5.6
+ version: 8.5.6
+ tailwindcss:
+ specifier: ^4.1.13
+ version: 4.1.13
+ typescript:
+ specifier: ~5.9.2
+ version: 5.9.2
+
+packages:
+
+ '@alloc/quick-lru@5.2.0':
+ resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
+ engines: {node: '>=10'}
+
+ '@emnapi/core@1.5.0':
+ resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==}
+
+ '@emnapi/runtime@1.5.0':
+ resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==}
+
+ '@emnapi/wasi-threads@1.1.0':
+ resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
+
+ '@eslint-community/eslint-utils@4.9.0':
+ resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
+ '@eslint-community/regexpp@4.12.1':
+ resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
+ '@eslint/config-array@0.21.0':
+ resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/config-helpers@0.3.1':
+ resolution: {integrity: sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/core@0.15.2':
+ resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/eslintrc@3.3.1':
+ resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/js@9.35.0':
+ resolution: {integrity: sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/object-schema@2.1.6':
+ resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/plugin-kit@0.3.5':
+ resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@humanfs/core@0.19.1':
+ resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
+ engines: {node: '>=18.18.0'}
+
+ '@humanfs/node@0.16.7':
+ resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==}
+ engines: {node: '>=18.18.0'}
+
+ '@humanwhocodes/module-importer@1.0.1':
+ resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+ engines: {node: '>=12.22'}
+
+ '@humanwhocodes/retry@0.4.3':
+ resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
+ engines: {node: '>=18.18'}
+
+ '@img/sharp-darwin-arm64@0.34.3':
+ resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@img/sharp-darwin-x64@0.34.3':
+ resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@img/sharp-libvips-darwin-arm64@1.2.0':
+ resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@img/sharp-libvips-darwin-x64@1.2.0':
+ resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@img/sharp-libvips-linux-arm64@1.2.0':
+ resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-arm@1.2.0':
+ resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==}
+ cpu: [arm]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-ppc64@1.2.0':
+ resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-s390x@1.2.0':
+ resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-x64@1.2.0':
+ resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-libvips-linuxmusl-arm64@1.2.0':
+ resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-libvips-linuxmusl-x64@1.2.0':
+ resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-linux-arm64@0.34.3':
+ resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-linux-arm@0.34.3':
+ resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@img/sharp-linux-ppc64@0.34.3':
+ resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@img/sharp-linux-s390x@0.34.3':
+ resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [s390x]
+ os: [linux]
+
+ '@img/sharp-linux-x64@0.34.3':
+ resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-linuxmusl-arm64@0.34.3':
+ resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-linuxmusl-x64@0.34.3':
+ resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-wasm32@0.34.3':
+ resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [wasm32]
+
+ '@img/sharp-win32-arm64@0.34.3':
+ resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@img/sharp-win32-ia32@0.34.3':
+ resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [ia32]
+ os: [win32]
+
+ '@img/sharp-win32-x64@0.34.3':
+ resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [win32]
+
+ '@isaacs/fs-minipass@4.0.1':
+ resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
+ engines: {node: '>=18.0.0'}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
+ '@napi-rs/wasm-runtime@0.2.12':
+ resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
+
+ '@next/env@15.5.3':
+ resolution: {integrity: sha512-RSEDTRqyihYXygx/OJXwvVupfr9m04+0vH8vyy0HfZ7keRto6VX9BbEk0J2PUk0VGy6YhklJUSrgForov5F9pw==}
+
+ '@next/eslint-plugin-next@15.5.3':
+ resolution: {integrity: sha512-SdhaKdko6dpsSr0DldkESItVrnPYB1NS2NpShCSX5lc7SSQmLZt5Mug6t2xbiuVWEVDLZSuIAoQyYVBYp0dR5g==}
+
+ '@next/swc-darwin-arm64@15.5.3':
+ resolution: {integrity: sha512-nzbHQo69+au9wJkGKTU9lP7PXv0d1J5ljFpvb+LnEomLtSbJkbZyEs6sbF3plQmiOB2l9OBtN2tNSvCH1nQ9Jg==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@next/swc-darwin-x64@15.5.3':
+ resolution: {integrity: sha512-w83w4SkOOhekJOcA5HBvHyGzgV1W/XvOfpkrxIse4uPWhYTTRwtGEM4v/jiXwNSJvfRvah0H8/uTLBKRXlef8g==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@next/swc-linux-arm64-gnu@15.5.3':
+ resolution: {integrity: sha512-+m7pfIs0/yvgVu26ieaKrifV8C8yiLe7jVp9SpcIzg7XmyyNE7toC1fy5IOQozmr6kWl/JONC51osih2RyoXRw==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@next/swc-linux-arm64-musl@15.5.3':
+ resolution: {integrity: sha512-u3PEIzuguSenoZviZJahNLgCexGFhso5mxWCrrIMdvpZn6lkME5vc/ADZG8UUk5K1uWRy4hqSFECrON6UKQBbQ==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@next/swc-linux-x64-gnu@15.5.3':
+ resolution: {integrity: sha512-lDtOOScYDZxI2BENN9m0pfVPJDSuUkAD1YXSvlJF0DKwZt0WlA7T7o3wrcEr4Q+iHYGzEaVuZcsIbCps4K27sA==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@next/swc-linux-x64-musl@15.5.3':
+ resolution: {integrity: sha512-9vWVUnsx9PrY2NwdVRJ4dUURAQ8Su0sLRPqcCCxtX5zIQUBES12eRVHq6b70bbfaVaxIDGJN2afHui0eDm+cLg==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@next/swc-win32-arm64-msvc@15.5.3':
+ resolution: {integrity: sha512-1CU20FZzY9LFQigRi6jM45oJMU3KziA5/sSG+dXeVaTm661snQP6xu3ykGxxwU5sLG3sh14teO/IOEPVsQMRfA==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@next/swc-win32-x64-msvc@15.5.3':
+ resolution: {integrity: sha512-JMoLAq3n3y5tKXPQwCK5c+6tmwkuFDa2XAxz8Wm4+IVthdBZdZGh+lmiLUHg9f9IDwIQpUjp+ysd6OkYTyZRZw==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@nodelib/fs.scandir@2.1.5':
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.stat@2.0.5':
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.walk@1.2.8':
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+
+ '@nolyfill/is-core-module@1.0.39':
+ resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
+ engines: {node: '>=12.4.0'}
+
+ '@rtsao/scc@1.1.0':
+ resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
+
+ '@rushstack/eslint-patch@1.12.0':
+ resolution: {integrity: sha512-5EwMtOqvJMMa3HbmxLlF74e+3/HhwBTMcvt3nqVJgGCozO6hzIPOBlwm8mGVNR9SN2IJpxSnlxczyDjcn7qIyw==}
+
+ '@swc/helpers@0.5.15':
+ resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
+
+ '@tailwindcss/forms@0.5.10':
+ resolution: {integrity: sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==}
+ peerDependencies:
+ tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1'
+
+ '@tailwindcss/node@4.1.13':
+ resolution: {integrity: sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==}
+
+ '@tailwindcss/oxide-android-arm64@4.1.13':
+ resolution: {integrity: sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [android]
+
+ '@tailwindcss/oxide-darwin-arm64@4.1.13':
+ resolution: {integrity: sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@tailwindcss/oxide-darwin-x64@4.1.13':
+ resolution: {integrity: sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@tailwindcss/oxide-freebsd-x64@4.1.13':
+ resolution: {integrity: sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13':
+ resolution: {integrity: sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==}
+ engines: {node: '>= 10'}
+ cpu: [arm]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-arm64-gnu@4.1.13':
+ resolution: {integrity: sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-arm64-musl@4.1.13':
+ resolution: {integrity: sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-x64-gnu@4.1.13':
+ resolution: {integrity: sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-x64-musl@4.1.13':
+ resolution: {integrity: sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@tailwindcss/oxide-wasm32-wasi@4.1.13':
+ resolution: {integrity: sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+ bundledDependencies:
+ - '@napi-rs/wasm-runtime'
+ - '@emnapi/core'
+ - '@emnapi/runtime'
+ - '@tybys/wasm-util'
+ - '@emnapi/wasi-threads'
+ - tslib
+
+ '@tailwindcss/oxide-win32-arm64-msvc@4.1.13':
+ resolution: {integrity: sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@tailwindcss/oxide-win32-x64-msvc@4.1.13':
+ resolution: {integrity: sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@tailwindcss/oxide@4.1.13':
+ resolution: {integrity: sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==}
+ engines: {node: '>= 10'}
+
+ '@tailwindcss/postcss@4.1.13':
+ resolution: {integrity: sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==}
+
+ '@tailwindcss/typography@0.5.16':
+ resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==}
+ peerDependencies:
+ tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
+
+ '@tybys/wasm-util@0.10.1':
+ resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
+
+ '@types/estree@1.0.8':
+ resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+
+ '@types/json-schema@7.0.15':
+ resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+
+ '@types/json5@0.0.29':
+ resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
+
+ '@types/node@24.3.3':
+ resolution: {integrity: sha512-GKBNHjoNw3Kra1Qg5UXttsY5kiWMEfoHq2TmXb+b1rcm6N7B3wTrFYIf/oSZ1xNQ+hVVijgLkiDZh7jRRsh+Gw==}
+
+ '@types/react-dom@19.1.9':
+ resolution: {integrity: sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==}
+ peerDependencies:
+ '@types/react': ^19.0.0
+
+ '@types/react@19.1.13':
+ resolution: {integrity: sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==}
+
+ '@typescript-eslint/eslint-plugin@8.43.0':
+ resolution: {integrity: sha512-8tg+gt7ENL7KewsKMKDHXR1vm8tt9eMxjJBYINf6swonlWgkYn5NwyIgXpbbDxTNU5DgpDFfj95prcTq2clIQQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^8.43.0
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/parser@8.43.0':
+ resolution: {integrity: sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/project-service@8.43.0':
+ resolution: {integrity: sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/scope-manager@8.43.0':
+ resolution: {integrity: sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/tsconfig-utils@8.43.0':
+ resolution: {integrity: sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/type-utils@8.43.0':
+ resolution: {integrity: sha512-qaH1uLBpBuBBuRf8c1mLJ6swOfzCXryhKND04Igr4pckzSEW9JX5Aw9AgW00kwfjWJF0kk0ps9ExKTfvXfw4Qg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/types@8.43.0':
+ resolution: {integrity: sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/typescript-estree@8.43.0':
+ resolution: {integrity: sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/utils@8.43.0':
+ resolution: {integrity: sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/visitor-keys@8.43.0':
+ resolution: {integrity: sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@unrs/resolver-binding-android-arm-eabi@1.11.1':
+ resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==}
+ cpu: [arm]
+ os: [android]
+
+ '@unrs/resolver-binding-android-arm64@1.11.1':
+ resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==}
+ cpu: [arm64]
+ os: [android]
+
+ '@unrs/resolver-binding-darwin-arm64@1.11.1':
+ resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@unrs/resolver-binding-darwin-x64@1.11.1':
+ resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@unrs/resolver-binding-freebsd-x64@1.11.1':
+ resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1':
+ resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==}
+ cpu: [arm]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1':
+ resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==}
+ cpu: [arm]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-arm64-gnu@1.11.1':
+ resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-arm64-musl@1.11.1':
+ resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
+ resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
+ resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
+ resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
+ resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-x64-gnu@1.11.1':
+ resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
+ cpu: [x64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-x64-musl@1.11.1':
+ resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
+ cpu: [x64]
+ os: [linux]
+
+ '@unrs/resolver-binding-wasm32-wasi@1.11.1':
+ resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
+ '@unrs/resolver-binding-win32-arm64-msvc@1.11.1':
+ resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@unrs/resolver-binding-win32-ia32-msvc@1.11.1':
+ resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@unrs/resolver-binding-win32-x64-msvc@1.11.1':
+ resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==}
+ cpu: [x64]
+ os: [win32]
+
+ acorn-jsx@5.3.2:
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+ acorn@8.15.0:
+ resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
+ ajv@6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+ aria-query@5.3.2:
+ resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
+ engines: {node: '>= 0.4'}
+
+ array-buffer-byte-length@1.0.2:
+ resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
+ engines: {node: '>= 0.4'}
+
+ array-includes@3.1.9:
+ resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.findlast@1.2.5:
+ resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.findlastindex@1.2.6:
+ resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.flat@1.3.3:
+ resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.flatmap@1.3.3:
+ resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.tosorted@1.1.4:
+ resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==}
+ engines: {node: '>= 0.4'}
+
+ arraybuffer.prototype.slice@1.0.4:
+ resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
+ engines: {node: '>= 0.4'}
+
+ ast-types-flow@0.0.8:
+ resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==}
+
+ async-function@1.0.0:
+ resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
+ engines: {node: '>= 0.4'}
+
+ autoprefixer@10.4.21:
+ resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==}
+ engines: {node: ^10 || ^12 || >=14}
+ hasBin: true
+ peerDependencies:
+ postcss: ^8.1.0
+
+ available-typed-arrays@1.0.7:
+ resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
+ engines: {node: '>= 0.4'}
+
+ axe-core@4.10.3:
+ resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==}
+ engines: {node: '>=4'}
+
+ axobject-query@4.1.0:
+ resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
+ engines: {node: '>= 0.4'}
+
+ balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ baseline-browser-mapping@2.8.3:
+ resolution: {integrity: sha512-mcE+Wr2CAhHNWxXN/DdTI+n4gsPc5QpXpWnyCQWiQYIYZX+ZMJ8juXZgjRa/0/YPJo/NSsgW15/YgmI4nbysYw==}
+ hasBin: true
+
+ brace-expansion@1.1.12:
+ resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
+
+ brace-expansion@2.0.2:
+ resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ browserslist@4.26.0:
+ resolution: {integrity: sha512-P9go2WrP9FiPwLv3zqRD/Uoxo0RSHjzFCiQz7d4vbmwNqQFo9T9WCeP/Qn5EbcKQY6DBbkxEXNcpJOmncNrb7A==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ call-bind-apply-helpers@1.0.2:
+ resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
+ engines: {node: '>= 0.4'}
+
+ call-bind@1.0.8:
+ resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
+ engines: {node: '>= 0.4'}
+
+ call-bound@1.0.4:
+ resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
+ engines: {node: '>= 0.4'}
+
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
+ caniuse-lite@1.0.30001741:
+ resolution: {integrity: sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==}
+
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+
+ chownr@3.0.0:
+ resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
+ engines: {node: '>=18'}
+
+ client-only@0.0.1:
+ resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ color-string@1.9.1:
+ resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
+
+ color@4.2.3:
+ resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
+ engines: {node: '>=12.5.0'}
+
+ concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+ engines: {node: '>= 8'}
+
+ cssesc@3.0.0:
+ resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ csstype@3.1.3:
+ resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+ damerau-levenshtein@1.0.8:
+ resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
+
+ data-view-buffer@1.0.2:
+ resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
+ engines: {node: '>= 0.4'}
+
+ data-view-byte-length@1.0.2:
+ resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==}
+ engines: {node: '>= 0.4'}
+
+ data-view-byte-offset@1.0.1:
+ resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
+ engines: {node: '>= 0.4'}
+
+ debug@3.2.7:
+ resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ deep-is@0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+
+ define-data-property@1.1.4:
+ resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
+ engines: {node: '>= 0.4'}
+
+ define-properties@1.2.1:
+ resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
+ engines: {node: '>= 0.4'}
+
+ detect-libc@2.0.4:
+ resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
+ engines: {node: '>=8'}
+
+ doctrine@2.1.0:
+ resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
+ engines: {node: '>=0.10.0'}
+
+ dunder-proto@1.0.1:
+ resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
+ engines: {node: '>= 0.4'}
+
+ electron-to-chromium@1.5.218:
+ resolution: {integrity: sha512-uwwdN0TUHs8u6iRgN8vKeWZMRll4gBkz+QMqdS7DDe49uiK68/UX92lFb61oiFPrpYZNeZIqa4bA7O6Aiasnzg==}
+
+ emoji-regex@9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+
+ enhanced-resolve@5.18.3:
+ resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
+ engines: {node: '>=10.13.0'}
+
+ es-abstract@1.24.0:
+ resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==}
+ engines: {node: '>= 0.4'}
+
+ es-define-property@1.0.1:
+ resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ es-iterator-helpers@1.2.1:
+ resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==}
+ engines: {node: '>= 0.4'}
+
+ es-object-atoms@1.1.1:
+ resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
+ engines: {node: '>= 0.4'}
+
+ es-set-tostringtag@2.1.0:
+ resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
+ engines: {node: '>= 0.4'}
+
+ es-shim-unscopables@1.1.0:
+ resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==}
+ engines: {node: '>= 0.4'}
+
+ es-to-primitive@1.3.0:
+ resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
+ engines: {node: '>= 0.4'}
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ eslint-config-next@15.5.3:
+ resolution: {integrity: sha512-e6j+QhQFOr5pfsc8VJbuTD9xTXJaRvMHYjEeLPA2pFkheNlgPLCkxdvhxhfuM4KGcqSZj2qEnpHisdTVs3BxuQ==}
+ peerDependencies:
+ eslint: ^7.23.0 || ^8.0.0 || ^9.0.0
+ typescript: '>=3.3.1'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ eslint-import-resolver-node@0.3.9:
+ resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
+
+ eslint-import-resolver-typescript@3.10.1:
+ resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ eslint: '*'
+ eslint-plugin-import: '*'
+ eslint-plugin-import-x: '*'
+ peerDependenciesMeta:
+ eslint-plugin-import:
+ optional: true
+ eslint-plugin-import-x:
+ optional: true
+
+ eslint-module-utils@2.12.1:
+ resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ '@typescript-eslint/parser': '*'
+ eslint: '*'
+ eslint-import-resolver-node: '*'
+ eslint-import-resolver-typescript: '*'
+ eslint-import-resolver-webpack: '*'
+ peerDependenciesMeta:
+ '@typescript-eslint/parser':
+ optional: true
+ eslint:
+ optional: true
+ eslint-import-resolver-node:
+ optional: true
+ eslint-import-resolver-typescript:
+ optional: true
+ eslint-import-resolver-webpack:
+ optional: true
+
+ eslint-plugin-import@2.32.0:
+ resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ '@typescript-eslint/parser': '*'
+ eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9
+ peerDependenciesMeta:
+ '@typescript-eslint/parser':
+ optional: true
+
+ eslint-plugin-jsx-a11y@6.10.2:
+ resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9
+
+ eslint-plugin-react-hooks@5.2.0:
+ resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
+
+ eslint-plugin-react@7.37.5:
+ resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
+
+ eslint-scope@8.4.0:
+ resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint-visitor-keys@3.4.3:
+ resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ eslint-visitor-keys@4.2.1:
+ resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint@9.35.0:
+ resolution: {integrity: sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ hasBin: true
+ peerDependencies:
+ jiti: '*'
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+
+ espree@10.4.0:
+ resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ esquery@1.6.0:
+ resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
+ engines: {node: '>=0.10'}
+
+ esrecurse@4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+
+ estraverse@5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+
+ esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+
+ fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+ fast-glob@3.3.1:
+ resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
+ engines: {node: '>=8.6.0'}
+
+ fast-glob@3.3.3:
+ resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
+ engines: {node: '>=8.6.0'}
+
+ fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+ fast-levenshtein@2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+
+ fastq@1.19.1:
+ resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
+
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ file-entry-cache@8.0.0:
+ resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
+ engines: {node: '>=16.0.0'}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+
+ flat-cache@4.0.1:
+ resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
+ engines: {node: '>=16'}
+
+ flatted@3.3.3:
+ resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+
+ for-each@0.3.5:
+ resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
+ engines: {node: '>= 0.4'}
+
+ fraction.js@4.3.7:
+ resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ function.prototype.name@1.1.8:
+ resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}
+ engines: {node: '>= 0.4'}
+
+ functions-have-names@1.2.3:
+ resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+
+ get-intrinsic@1.3.0:
+ resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
+ engines: {node: '>= 0.4'}
+
+ get-proto@1.0.1:
+ resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
+ engines: {node: '>= 0.4'}
+
+ get-symbol-description@1.1.0:
+ resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
+ engines: {node: '>= 0.4'}
+
+ get-tsconfig@4.10.1:
+ resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==}
+
+ glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+
+ glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+
+ globals@14.0.0:
+ resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
+ engines: {node: '>=18'}
+
+ globalthis@1.0.4:
+ resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
+ engines: {node: '>= 0.4'}
+
+ gopd@1.2.0:
+ resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
+ engines: {node: '>= 0.4'}
+
+ graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+ graphemer@1.4.0:
+ resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+
+ has-bigints@1.1.0:
+ resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
+ engines: {node: '>= 0.4'}
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ has-property-descriptors@1.0.2:
+ resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+
+ has-proto@1.2.0:
+ resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==}
+ engines: {node: '>= 0.4'}
+
+ has-symbols@1.1.0:
+ resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
+ engines: {node: '>= 0.4'}
+
+ has-tostringtag@1.0.2:
+ resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+ engines: {node: '>= 0.4'}
+
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ ignore@5.3.2:
+ resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
+ engines: {node: '>= 4'}
+
+ ignore@7.0.5:
+ resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
+ engines: {node: '>= 4'}
+
+ import-fresh@3.3.1:
+ resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
+ engines: {node: '>=6'}
+
+ imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+
+ internal-slot@1.1.0:
+ resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
+ engines: {node: '>= 0.4'}
+
+ is-array-buffer@3.0.5:
+ resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
+ engines: {node: '>= 0.4'}
+
+ is-arrayish@0.3.4:
+ resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==}
+
+ is-async-function@2.1.1:
+ resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==}
+ engines: {node: '>= 0.4'}
+
+ is-bigint@1.1.0:
+ resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==}
+ engines: {node: '>= 0.4'}
+
+ is-boolean-object@1.2.2:
+ resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
+ engines: {node: '>= 0.4'}
+
+ is-bun-module@2.0.0:
+ resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==}
+
+ is-callable@1.2.7:
+ resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
+ engines: {node: '>= 0.4'}
+
+ is-core-module@2.16.1:
+ resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
+ engines: {node: '>= 0.4'}
+
+ is-data-view@1.0.2:
+ resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==}
+ engines: {node: '>= 0.4'}
+
+ is-date-object@1.1.0:
+ resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
+ engines: {node: '>= 0.4'}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-finalizationregistry@1.1.1:
+ resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==}
+ engines: {node: '>= 0.4'}
+
+ is-generator-function@1.1.0:
+ resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==}
+ engines: {node: '>= 0.4'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-map@2.0.3:
+ resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
+ engines: {node: '>= 0.4'}
+
+ is-negative-zero@2.0.3:
+ resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
+ engines: {node: '>= 0.4'}
+
+ is-number-object@1.1.1:
+ resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
+ engines: {node: '>= 0.4'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ is-regex@1.2.1:
+ resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
+ engines: {node: '>= 0.4'}
+
+ is-set@2.0.3:
+ resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
+ engines: {node: '>= 0.4'}
+
+ is-shared-array-buffer@1.0.4:
+ resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
+ engines: {node: '>= 0.4'}
+
+ is-string@1.1.1:
+ resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
+ engines: {node: '>= 0.4'}
+
+ is-symbol@1.1.1:
+ resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
+ engines: {node: '>= 0.4'}
+
+ is-typed-array@1.1.15:
+ resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
+ engines: {node: '>= 0.4'}
+
+ is-weakmap@2.0.2:
+ resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
+ engines: {node: '>= 0.4'}
+
+ is-weakref@1.1.1:
+ resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==}
+ engines: {node: '>= 0.4'}
+
+ is-weakset@2.0.4:
+ resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
+ engines: {node: '>= 0.4'}
+
+ isarray@2.0.5:
+ resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ iterator.prototype@1.1.5:
+ resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==}
+ engines: {node: '>= 0.4'}
+
+ jiti@2.5.1:
+ resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==}
+ hasBin: true
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-yaml@4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+
+ json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+
+ json-schema-traverse@0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+ json-stable-stringify-without-jsonify@1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+
+ json5@1.0.2:
+ resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
+ hasBin: true
+
+ jsx-ast-utils@3.3.5:
+ resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
+ engines: {node: '>=4.0'}
+
+ keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+
+ language-subtag-registry@0.3.23:
+ resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==}
+
+ language-tags@1.0.9:
+ resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==}
+ engines: {node: '>=0.10'}
+
+ levn@0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+
+ lightningcss-darwin-arm64@1.30.1:
+ resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ lightningcss-darwin-x64@1.30.1:
+ resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ lightningcss-freebsd-x64@1.30.1:
+ resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ lightningcss-linux-arm-gnueabihf@1.30.1:
+ resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ lightningcss-linux-arm64-gnu@1.30.1:
+ resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-arm64-musl@1.30.1:
+ resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-x64-gnu@1.30.1:
+ resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-linux-x64-musl@1.30.1:
+ resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-win32-arm64-msvc@1.30.1:
+ resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ lightningcss-win32-x64-msvc@1.30.1:
+ resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ lightningcss@1.30.1:
+ resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
+ engines: {node: '>= 12.0.0'}
+
+ locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+
+ lodash.castarray@4.4.0:
+ resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
+
+ lodash.isplainobject@4.0.6:
+ resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
+
+ lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
+ loose-envify@1.4.0:
+ resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+ hasBin: true
+
+ lucide-react@0.544.0:
+ resolution: {integrity: sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw==}
+ peerDependencies:
+ react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
+ magic-string@0.30.19:
+ resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==}
+
+ math-intrinsics@1.1.0:
+ resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
+ engines: {node: '>= 0.4'}
+
+ merge2@1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ mini-svg-data-uri@1.4.4:
+ resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
+ hasBin: true
+
+ minimatch@3.1.2:
+ resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+
+ minimatch@9.0.5:
+ resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ minimist@1.2.8:
+ resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+
+ minipass@7.1.2:
+ resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ minizlib@3.0.2:
+ resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==}
+ engines: {node: '>= 18'}
+
+ mkdirp@3.0.1:
+ resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ napi-postinstall@0.3.3:
+ resolution: {integrity: sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==}
+ engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
+ hasBin: true
+
+ natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
+ next@15.5.3:
+ resolution: {integrity: sha512-r/liNAx16SQj4D+XH/oI1dlpv9tdKJ6cONYPwwcCC46f2NjpaRWY+EKCzULfgQYV6YKXjHBchff2IZBSlZmJNw==}
+ engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@opentelemetry/api': ^1.1.0
+ '@playwright/test': ^1.51.1
+ babel-plugin-react-compiler: '*'
+ react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
+ react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
+ sass: ^1.3.0
+ peerDependenciesMeta:
+ '@opentelemetry/api':
+ optional: true
+ '@playwright/test':
+ optional: true
+ babel-plugin-react-compiler:
+ optional: true
+ sass:
+ optional: true
+
+ node-releases@2.0.21:
+ resolution: {integrity: sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==}
+
+ normalize-range@0.1.2:
+ resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
+ engines: {node: '>=0.10.0'}
+
+ object-assign@4.1.1:
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+ engines: {node: '>=0.10.0'}
+
+ object-inspect@1.13.4:
+ resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
+ engines: {node: '>= 0.4'}
+
+ object-keys@1.1.1:
+ resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+ engines: {node: '>= 0.4'}
+
+ object.assign@4.1.7:
+ resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
+ engines: {node: '>= 0.4'}
+
+ object.entries@1.1.9:
+ resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==}
+ engines: {node: '>= 0.4'}
+
+ object.fromentries@2.0.8:
+ resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==}
+ engines: {node: '>= 0.4'}
+
+ object.groupby@1.0.3:
+ resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==}
+ engines: {node: '>= 0.4'}
+
+ object.values@1.2.1:
+ resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
+ engines: {node: '>= 0.4'}
+
+ optionator@0.9.4:
+ resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
+ engines: {node: '>= 0.8.0'}
+
+ own-keys@1.0.1:
+ resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
+ engines: {node: '>= 0.4'}
+
+ p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+
+ p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+
+ parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ picomatch@4.0.3:
+ resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
+ engines: {node: '>=12'}
+
+ possible-typed-array-names@1.1.0:
+ resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
+ engines: {node: '>= 0.4'}
+
+ postcss-selector-parser@6.0.10:
+ resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
+ engines: {node: '>=4'}
+
+ postcss-value-parser@4.2.0:
+ resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+
+ postcss@8.4.31:
+ resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ postcss@8.5.6:
+ resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ prelude-ls@1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+
+ prop-types@15.8.1:
+ resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+
+ punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+
+ queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
+ react-dom@19.1.1:
+ resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==}
+ peerDependencies:
+ react: ^19.1.1
+
+ react-is@16.13.1:
+ resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+
+ react@19.1.1:
+ resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==}
+ engines: {node: '>=0.10.0'}
+
+ reflect.getprototypeof@1.0.10:
+ resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
+ engines: {node: '>= 0.4'}
+
+ regexp.prototype.flags@1.5.4:
+ resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
+ engines: {node: '>= 0.4'}
+
+ resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
+ resolve-pkg-maps@1.0.0:
+ resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+
+ resolve@1.22.10:
+ resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
+ engines: {node: '>= 0.4'}
+ hasBin: true
+
+ resolve@2.0.0-next.5:
+ resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==}
+ hasBin: true
+
+ reusify@1.1.0:
+ resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+ run-parallel@1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+
+ safe-array-concat@1.1.3:
+ resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
+ engines: {node: '>=0.4'}
+
+ safe-push-apply@1.0.0:
+ resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
+ engines: {node: '>= 0.4'}
+
+ safe-regex-test@1.1.0:
+ resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
+ engines: {node: '>= 0.4'}
+
+ scheduler@0.26.0:
+ resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ semver@7.7.2:
+ resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ set-function-length@1.2.2:
+ resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+ engines: {node: '>= 0.4'}
+
+ set-function-name@2.0.2:
+ resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
+ engines: {node: '>= 0.4'}
+
+ set-proto@1.0.0:
+ resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
+ engines: {node: '>= 0.4'}
+
+ sharp@0.34.3:
+ resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ side-channel-list@1.0.0:
+ resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-map@1.0.1:
+ resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-weakmap@1.0.2:
+ resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
+ engines: {node: '>= 0.4'}
+
+ side-channel@1.1.0:
+ resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
+ engines: {node: '>= 0.4'}
+
+ simple-swizzle@0.2.4:
+ resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ stable-hash@0.0.5:
+ resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
+
+ stop-iteration-iterator@1.1.0:
+ resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.includes@2.0.1:
+ resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.matchall@4.0.12:
+ resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.repeat@1.0.0:
+ resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==}
+
+ string.prototype.trim@1.2.10:
+ resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.trimend@1.0.9:
+ resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.trimstart@1.0.8:
+ resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
+ engines: {node: '>= 0.4'}
+
+ strip-bom@3.0.0:
+ resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
+ engines: {node: '>=4'}
+
+ strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+
+ styled-jsx@5.1.6:
+ resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
+ engines: {node: '>= 12.0.0'}
+ peerDependencies:
+ '@babel/core': '*'
+ babel-plugin-macros: '*'
+ react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0'
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ babel-plugin-macros:
+ optional: true
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+
+ tailwindcss@4.1.13:
+ resolution: {integrity: sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==}
+
+ tapable@2.2.3:
+ resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==}
+ engines: {node: '>=6'}
+
+ tar@7.4.3:
+ resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
+ engines: {node: '>=18'}
+
+ tinyglobby@0.2.15:
+ resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
+ engines: {node: '>=12.0.0'}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ ts-api-utils@2.1.0:
+ resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
+ engines: {node: '>=18.12'}
+ peerDependencies:
+ typescript: '>=4.8.4'
+
+ tsconfig-paths@3.15.0:
+ resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ type-check@0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+
+ typed-array-buffer@1.0.3:
+ resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
+ engines: {node: '>= 0.4'}
+
+ typed-array-byte-length@1.0.3:
+ resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==}
+ engines: {node: '>= 0.4'}
+
+ typed-array-byte-offset@1.0.4:
+ resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}
+ engines: {node: '>= 0.4'}
+
+ typed-array-length@1.0.7:
+ resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
+ engines: {node: '>= 0.4'}
+
+ typescript@5.9.2:
+ resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ unbox-primitive@1.1.0:
+ resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
+ engines: {node: '>= 0.4'}
+
+ undici-types@7.10.0:
+ resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==}
+
+ unrs-resolver@1.11.1:
+ resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==}
+
+ update-browserslist-db@1.1.3:
+ resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
+ util-deprecate@1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
+ which-boxed-primitive@1.1.1:
+ resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
+ engines: {node: '>= 0.4'}
+
+ which-builtin-type@1.2.1:
+ resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==}
+ engines: {node: '>= 0.4'}
+
+ which-collection@1.0.2:
+ resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
+ engines: {node: '>= 0.4'}
+
+ which-typed-array@1.1.19:
+ resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
+ engines: {node: '>= 0.4'}
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
+ word-wrap@1.2.5:
+ resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
+ engines: {node: '>=0.10.0'}
+
+ yallist@5.0.0:
+ resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
+ engines: {node: '>=18'}
+
+ yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+
+snapshots:
+
+ '@alloc/quick-lru@5.2.0': {}
+
+ '@emnapi/core@1.5.0':
+ dependencies:
+ '@emnapi/wasi-threads': 1.1.0
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/runtime@1.5.0':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/wasi-threads@1.1.0':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@eslint-community/eslint-utils@4.9.0(eslint@9.35.0(jiti@2.5.1))':
+ dependencies:
+ eslint: 9.35.0(jiti@2.5.1)
+ eslint-visitor-keys: 3.4.3
+
+ '@eslint-community/regexpp@4.12.1': {}
+
+ '@eslint/config-array@0.21.0':
+ dependencies:
+ '@eslint/object-schema': 2.1.6
+ debug: 4.4.3
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/config-helpers@0.3.1': {}
+
+ '@eslint/core@0.15.2':
+ dependencies:
+ '@types/json-schema': 7.0.15
+
+ '@eslint/eslintrc@3.3.1':
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.4.3
+ espree: 10.4.0
+ globals: 14.0.0
+ ignore: 5.3.2
+ import-fresh: 3.3.1
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/js@9.35.0': {}
+
+ '@eslint/object-schema@2.1.6': {}
+
+ '@eslint/plugin-kit@0.3.5':
+ dependencies:
+ '@eslint/core': 0.15.2
+ levn: 0.4.1
+
+ '@humanfs/core@0.19.1': {}
+
+ '@humanfs/node@0.16.7':
+ dependencies:
+ '@humanfs/core': 0.19.1
+ '@humanwhocodes/retry': 0.4.3
+
+ '@humanwhocodes/module-importer@1.0.1': {}
+
+ '@humanwhocodes/retry@0.4.3': {}
+
+ '@img/sharp-darwin-arm64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-arm64': 1.2.0
+ optional: true
+
+ '@img/sharp-darwin-x64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-x64': 1.2.0
+ optional: true
+
+ '@img/sharp-libvips-darwin-arm64@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-darwin-x64@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-arm64@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-arm@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-ppc64@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-s390x@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-x64@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linuxmusl-arm64@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linuxmusl-x64@1.2.0':
+ optional: true
+
+ '@img/sharp-linux-arm64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm64': 1.2.0
+ optional: true
+
+ '@img/sharp-linux-arm@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm': 1.2.0
+ optional: true
+
+ '@img/sharp-linux-ppc64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-ppc64': 1.2.0
+ optional: true
+
+ '@img/sharp-linux-s390x@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-s390x': 1.2.0
+ optional: true
+
+ '@img/sharp-linux-x64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-x64': 1.2.0
+ optional: true
+
+ '@img/sharp-linuxmusl-arm64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-arm64': 1.2.0
+ optional: true
+
+ '@img/sharp-linuxmusl-x64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-x64': 1.2.0
+ optional: true
+
+ '@img/sharp-wasm32@0.34.3':
+ dependencies:
+ '@emnapi/runtime': 1.5.0
+ optional: true
+
+ '@img/sharp-win32-arm64@0.34.3':
+ optional: true
+
+ '@img/sharp-win32-ia32@0.34.3':
+ optional: true
+
+ '@img/sharp-win32-x64@0.34.3':
+ optional: true
+
+ '@isaacs/fs-minipass@4.0.1':
+ dependencies:
+ minipass: 7.1.2
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@napi-rs/wasm-runtime@0.2.12':
+ dependencies:
+ '@emnapi/core': 1.5.0
+ '@emnapi/runtime': 1.5.0
+ '@tybys/wasm-util': 0.10.1
+ optional: true
+
+ '@next/env@15.5.3': {}
+
+ '@next/eslint-plugin-next@15.5.3':
+ dependencies:
+ fast-glob: 3.3.1
+
+ '@next/swc-darwin-arm64@15.5.3':
+ optional: true
+
+ '@next/swc-darwin-x64@15.5.3':
+ optional: true
+
+ '@next/swc-linux-arm64-gnu@15.5.3':
+ optional: true
+
+ '@next/swc-linux-arm64-musl@15.5.3':
+ optional: true
+
+ '@next/swc-linux-x64-gnu@15.5.3':
+ optional: true
+
+ '@next/swc-linux-x64-musl@15.5.3':
+ optional: true
+
+ '@next/swc-win32-arm64-msvc@15.5.3':
+ optional: true
+
+ '@next/swc-win32-x64-msvc@15.5.3':
+ optional: true
+
+ '@nodelib/fs.scandir@2.1.5':
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+
+ '@nodelib/fs.stat@2.0.5': {}
+
+ '@nodelib/fs.walk@1.2.8':
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.19.1
+
+ '@nolyfill/is-core-module@1.0.39': {}
+
+ '@rtsao/scc@1.1.0': {}
+
+ '@rushstack/eslint-patch@1.12.0': {}
+
+ '@swc/helpers@0.5.15':
+ dependencies:
+ tslib: 2.8.1
+
+ '@tailwindcss/forms@0.5.10(tailwindcss@4.1.13)':
+ dependencies:
+ mini-svg-data-uri: 1.4.4
+ tailwindcss: 4.1.13
+
+ '@tailwindcss/node@4.1.13':
+ dependencies:
+ '@jridgewell/remapping': 2.3.5
+ enhanced-resolve: 5.18.3
+ jiti: 2.5.1
+ lightningcss: 1.30.1
+ magic-string: 0.30.19
+ source-map-js: 1.2.1
+ tailwindcss: 4.1.13
+
+ '@tailwindcss/oxide-android-arm64@4.1.13':
+ optional: true
+
+ '@tailwindcss/oxide-darwin-arm64@4.1.13':
+ optional: true
+
+ '@tailwindcss/oxide-darwin-x64@4.1.13':
+ optional: true
+
+ '@tailwindcss/oxide-freebsd-x64@4.1.13':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm64-gnu@4.1.13':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm64-musl@4.1.13':
+ optional: true
+
+ '@tailwindcss/oxide-linux-x64-gnu@4.1.13':
+ optional: true
+
+ '@tailwindcss/oxide-linux-x64-musl@4.1.13':
+ optional: true
+
+ '@tailwindcss/oxide-wasm32-wasi@4.1.13':
+ optional: true
+
+ '@tailwindcss/oxide-win32-arm64-msvc@4.1.13':
+ optional: true
+
+ '@tailwindcss/oxide-win32-x64-msvc@4.1.13':
+ optional: true
+
+ '@tailwindcss/oxide@4.1.13':
+ dependencies:
+ detect-libc: 2.0.4
+ tar: 7.4.3
+ optionalDependencies:
+ '@tailwindcss/oxide-android-arm64': 4.1.13
+ '@tailwindcss/oxide-darwin-arm64': 4.1.13
+ '@tailwindcss/oxide-darwin-x64': 4.1.13
+ '@tailwindcss/oxide-freebsd-x64': 4.1.13
+ '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.13
+ '@tailwindcss/oxide-linux-arm64-gnu': 4.1.13
+ '@tailwindcss/oxide-linux-arm64-musl': 4.1.13
+ '@tailwindcss/oxide-linux-x64-gnu': 4.1.13
+ '@tailwindcss/oxide-linux-x64-musl': 4.1.13
+ '@tailwindcss/oxide-wasm32-wasi': 4.1.13
+ '@tailwindcss/oxide-win32-arm64-msvc': 4.1.13
+ '@tailwindcss/oxide-win32-x64-msvc': 4.1.13
+
+ '@tailwindcss/postcss@4.1.13':
+ dependencies:
+ '@alloc/quick-lru': 5.2.0
+ '@tailwindcss/node': 4.1.13
+ '@tailwindcss/oxide': 4.1.13
+ postcss: 8.5.6
+ tailwindcss: 4.1.13
+
+ '@tailwindcss/typography@0.5.16(tailwindcss@4.1.13)':
+ dependencies:
+ lodash.castarray: 4.4.0
+ lodash.isplainobject: 4.0.6
+ lodash.merge: 4.6.2
+ postcss-selector-parser: 6.0.10
+ tailwindcss: 4.1.13
+
+ '@tybys/wasm-util@0.10.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@types/estree@1.0.8': {}
+
+ '@types/json-schema@7.0.15': {}
+
+ '@types/json5@0.0.29': {}
+
+ '@types/node@24.3.3':
+ dependencies:
+ undici-types: 7.10.0
+
+ '@types/react-dom@19.1.9(@types/react@19.1.13)':
+ dependencies:
+ '@types/react': 19.1.13
+
+ '@types/react@19.1.13':
+ dependencies:
+ csstype: 3.1.3
+
+ '@typescript-eslint/eslint-plugin@8.43.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)':
+ dependencies:
+ '@eslint-community/regexpp': 4.12.1
+ '@typescript-eslint/parser': 8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)
+ '@typescript-eslint/scope-manager': 8.43.0
+ '@typescript-eslint/type-utils': 8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)
+ '@typescript-eslint/utils': 8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)
+ '@typescript-eslint/visitor-keys': 8.43.0
+ eslint: 9.35.0(jiti@2.5.1)
+ graphemer: 1.4.0
+ ignore: 7.0.5
+ natural-compare: 1.4.0
+ ts-api-utils: 2.1.0(typescript@5.9.2)
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/parser@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)':
+ dependencies:
+ '@typescript-eslint/scope-manager': 8.43.0
+ '@typescript-eslint/types': 8.43.0
+ '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.2)
+ '@typescript-eslint/visitor-keys': 8.43.0
+ debug: 4.4.3
+ eslint: 9.35.0(jiti@2.5.1)
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/project-service@8.43.0(typescript@5.9.2)':
+ dependencies:
+ '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.9.2)
+ '@typescript-eslint/types': 8.43.0
+ debug: 4.4.3
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/scope-manager@8.43.0':
+ dependencies:
+ '@typescript-eslint/types': 8.43.0
+ '@typescript-eslint/visitor-keys': 8.43.0
+
+ '@typescript-eslint/tsconfig-utils@8.43.0(typescript@5.9.2)':
+ dependencies:
+ typescript: 5.9.2
+
+ '@typescript-eslint/type-utils@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)':
+ dependencies:
+ '@typescript-eslint/types': 8.43.0
+ '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.2)
+ '@typescript-eslint/utils': 8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)
+ debug: 4.4.3
+ eslint: 9.35.0(jiti@2.5.1)
+ ts-api-utils: 2.1.0(typescript@5.9.2)
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/types@8.43.0': {}
+
+ '@typescript-eslint/typescript-estree@8.43.0(typescript@5.9.2)':
+ dependencies:
+ '@typescript-eslint/project-service': 8.43.0(typescript@5.9.2)
+ '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.9.2)
+ '@typescript-eslint/types': 8.43.0
+ '@typescript-eslint/visitor-keys': 8.43.0
+ debug: 4.4.3
+ fast-glob: 3.3.3
+ is-glob: 4.0.3
+ minimatch: 9.0.5
+ semver: 7.7.2
+ ts-api-utils: 2.1.0(typescript@5.9.2)
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/utils@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)':
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.0(eslint@9.35.0(jiti@2.5.1))
+ '@typescript-eslint/scope-manager': 8.43.0
+ '@typescript-eslint/types': 8.43.0
+ '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.2)
+ eslint: 9.35.0(jiti@2.5.1)
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/visitor-keys@8.43.0':
+ dependencies:
+ '@typescript-eslint/types': 8.43.0
+ eslint-visitor-keys: 4.2.1
+
+ '@unrs/resolver-binding-android-arm-eabi@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-android-arm64@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-darwin-arm64@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-darwin-x64@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-freebsd-x64@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-arm64-gnu@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-arm64-musl@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-x64-gnu@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-x64-musl@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-wasm32-wasi@1.11.1':
+ dependencies:
+ '@napi-rs/wasm-runtime': 0.2.12
+ optional: true
+
+ '@unrs/resolver-binding-win32-arm64-msvc@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-win32-ia32-msvc@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-win32-x64-msvc@1.11.1':
+ optional: true
+
+ acorn-jsx@5.3.2(acorn@8.15.0):
+ dependencies:
+ acorn: 8.15.0
+
+ acorn@8.15.0: {}
+
+ ajv@6.12.6:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ argparse@2.0.1: {}
+
+ aria-query@5.3.2: {}
+
+ array-buffer-byte-length@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ is-array-buffer: 3.0.5
+
+ array-includes@3.1.9:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-object-atoms: 1.1.1
+ get-intrinsic: 1.3.0
+ is-string: 1.1.1
+ math-intrinsics: 1.1.0
+
+ array.prototype.findlast@1.2.5:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ es-shim-unscopables: 1.1.0
+
+ array.prototype.findlastindex@1.2.6:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ es-shim-unscopables: 1.1.0
+
+ array.prototype.flat@1.3.3:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-shim-unscopables: 1.1.0
+
+ array.prototype.flatmap@1.3.3:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-shim-unscopables: 1.1.0
+
+ array.prototype.tosorted@1.1.4:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ es-shim-unscopables: 1.1.0
+
+ arraybuffer.prototype.slice@1.0.4:
+ dependencies:
+ array-buffer-byte-length: 1.0.2
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ is-array-buffer: 3.0.5
+
+ ast-types-flow@0.0.8: {}
+
+ async-function@1.0.0: {}
+
+ autoprefixer@10.4.21(postcss@8.5.6):
+ dependencies:
+ browserslist: 4.26.0
+ caniuse-lite: 1.0.30001741
+ fraction.js: 4.3.7
+ normalize-range: 0.1.2
+ picocolors: 1.1.1
+ postcss: 8.5.6
+ postcss-value-parser: 4.2.0
+
+ available-typed-arrays@1.0.7:
+ dependencies:
+ possible-typed-array-names: 1.1.0
+
+ axe-core@4.10.3: {}
+
+ axobject-query@4.1.0: {}
+
+ balanced-match@1.0.2: {}
+
+ baseline-browser-mapping@2.8.3: {}
+
+ brace-expansion@1.1.12:
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+
+ brace-expansion@2.0.2:
+ dependencies:
+ balanced-match: 1.0.2
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ browserslist@4.26.0:
+ dependencies:
+ baseline-browser-mapping: 2.8.3
+ caniuse-lite: 1.0.30001741
+ electron-to-chromium: 1.5.218
+ node-releases: 2.0.21
+ update-browserslist-db: 1.1.3(browserslist@4.26.0)
+
+ call-bind-apply-helpers@1.0.2:
+ dependencies:
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+
+ call-bind@1.0.8:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-define-property: 1.0.1
+ get-intrinsic: 1.3.0
+ set-function-length: 1.2.2
+
+ call-bound@1.0.4:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ get-intrinsic: 1.3.0
+
+ callsites@3.1.0: {}
+
+ caniuse-lite@1.0.30001741: {}
+
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ chownr@3.0.0: {}
+
+ client-only@0.0.1: {}
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ color-string@1.9.1:
+ dependencies:
+ color-name: 1.1.4
+ simple-swizzle: 0.2.4
+ optional: true
+
+ color@4.2.3:
+ dependencies:
+ color-convert: 2.0.1
+ color-string: 1.9.1
+ optional: true
+
+ concat-map@0.0.1: {}
+
+ cross-spawn@7.0.6:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ cssesc@3.0.0: {}
+
+ csstype@3.1.3: {}
+
+ damerau-levenshtein@1.0.8: {}
+
+ data-view-buffer@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-data-view: 1.0.2
+
+ data-view-byte-length@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-data-view: 1.0.2
+
+ data-view-byte-offset@1.0.1:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-data-view: 1.0.2
+
+ debug@3.2.7:
+ dependencies:
+ ms: 2.1.3
+
+ debug@4.4.3:
+ dependencies:
+ ms: 2.1.3
+
+ deep-is@0.1.4: {}
+
+ define-data-property@1.1.4:
+ dependencies:
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ gopd: 1.2.0
+
+ define-properties@1.2.1:
+ dependencies:
+ define-data-property: 1.1.4
+ has-property-descriptors: 1.0.2
+ object-keys: 1.1.1
+
+ detect-libc@2.0.4: {}
+
+ doctrine@2.1.0:
+ dependencies:
+ esutils: 2.0.3
+
+ dunder-proto@1.0.1:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-errors: 1.3.0
+ gopd: 1.2.0
+
+ electron-to-chromium@1.5.218: {}
+
+ emoji-regex@9.2.2: {}
+
+ enhanced-resolve@5.18.3:
+ dependencies:
+ graceful-fs: 4.2.11
+ tapable: 2.2.3
+
+ es-abstract@1.24.0:
+ dependencies:
+ array-buffer-byte-length: 1.0.2
+ arraybuffer.prototype.slice: 1.0.4
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ data-view-buffer: 1.0.2
+ data-view-byte-length: 1.0.2
+ data-view-byte-offset: 1.0.1
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ es-set-tostringtag: 2.1.0
+ es-to-primitive: 1.3.0
+ function.prototype.name: 1.1.8
+ get-intrinsic: 1.3.0
+ get-proto: 1.0.1
+ get-symbol-description: 1.1.0
+ globalthis: 1.0.4
+ gopd: 1.2.0
+ has-property-descriptors: 1.0.2
+ has-proto: 1.2.0
+ has-symbols: 1.1.0
+ hasown: 2.0.2
+ internal-slot: 1.1.0
+ is-array-buffer: 3.0.5
+ is-callable: 1.2.7
+ is-data-view: 1.0.2
+ is-negative-zero: 2.0.3
+ is-regex: 1.2.1
+ is-set: 2.0.3
+ is-shared-array-buffer: 1.0.4
+ is-string: 1.1.1
+ is-typed-array: 1.1.15
+ is-weakref: 1.1.1
+ math-intrinsics: 1.1.0
+ object-inspect: 1.13.4
+ object-keys: 1.1.1
+ object.assign: 4.1.7
+ own-keys: 1.0.1
+ regexp.prototype.flags: 1.5.4
+ safe-array-concat: 1.1.3
+ safe-push-apply: 1.0.0
+ safe-regex-test: 1.1.0
+ set-proto: 1.0.0
+ stop-iteration-iterator: 1.1.0
+ string.prototype.trim: 1.2.10
+ string.prototype.trimend: 1.0.9
+ string.prototype.trimstart: 1.0.8
+ typed-array-buffer: 1.0.3
+ typed-array-byte-length: 1.0.3
+ typed-array-byte-offset: 1.0.4
+ typed-array-length: 1.0.7
+ unbox-primitive: 1.1.0
+ which-typed-array: 1.1.19
+
+ es-define-property@1.0.1: {}
+
+ es-errors@1.3.0: {}
+
+ es-iterator-helpers@1.2.1:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ es-set-tostringtag: 2.1.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.3.0
+ globalthis: 1.0.4
+ gopd: 1.2.0
+ has-property-descriptors: 1.0.2
+ has-proto: 1.2.0
+ has-symbols: 1.1.0
+ internal-slot: 1.1.0
+ iterator.prototype: 1.1.5
+ safe-array-concat: 1.1.3
+
+ es-object-atoms@1.1.1:
+ dependencies:
+ es-errors: 1.3.0
+
+ es-set-tostringtag@2.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
+
+ es-shim-unscopables@1.1.0:
+ dependencies:
+ hasown: 2.0.2
+
+ es-to-primitive@1.3.0:
+ dependencies:
+ is-callable: 1.2.7
+ is-date-object: 1.1.0
+ is-symbol: 1.1.1
+
+ escalade@3.2.0: {}
+
+ escape-string-regexp@4.0.0: {}
+
+ eslint-config-next@15.5.3(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2):
+ dependencies:
+ '@next/eslint-plugin-next': 15.5.3
+ '@rushstack/eslint-patch': 1.12.0
+ '@typescript-eslint/eslint-plugin': 8.43.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)
+ '@typescript-eslint/parser': 8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)
+ eslint: 9.35.0(jiti@2.5.1)
+ eslint-import-resolver-node: 0.3.9
+ eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.35.0(jiti@2.5.1))
+ eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1))
+ eslint-plugin-jsx-a11y: 6.10.2(eslint@9.35.0(jiti@2.5.1))
+ eslint-plugin-react: 7.37.5(eslint@9.35.0(jiti@2.5.1))
+ eslint-plugin-react-hooks: 5.2.0(eslint@9.35.0(jiti@2.5.1))
+ optionalDependencies:
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - eslint-import-resolver-webpack
+ - eslint-plugin-import-x
+ - supports-color
+
+ eslint-import-resolver-node@0.3.9:
+ dependencies:
+ debug: 3.2.7
+ is-core-module: 2.16.1
+ resolve: 1.22.10
+ transitivePeerDependencies:
+ - supports-color
+
+ eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.35.0(jiti@2.5.1)):
+ dependencies:
+ '@nolyfill/is-core-module': 1.0.39
+ debug: 4.4.3
+ eslint: 9.35.0(jiti@2.5.1)
+ get-tsconfig: 4.10.1
+ is-bun-module: 2.0.0
+ stable-hash: 0.0.5
+ tinyglobby: 0.2.15
+ unrs-resolver: 1.11.1
+ optionalDependencies:
+ eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1))
+ transitivePeerDependencies:
+ - supports-color
+
+ eslint-module-utils@2.12.1(@typescript-eslint/parser@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1)):
+ dependencies:
+ debug: 3.2.7
+ optionalDependencies:
+ '@typescript-eslint/parser': 8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)
+ eslint: 9.35.0(jiti@2.5.1)
+ eslint-import-resolver-node: 0.3.9
+ eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.35.0(jiti@2.5.1))
+ transitivePeerDependencies:
+ - supports-color
+
+ eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1)):
+ dependencies:
+ '@rtsao/scc': 1.1.0
+ array-includes: 3.1.9
+ array.prototype.findlastindex: 1.2.6
+ array.prototype.flat: 1.3.3
+ array.prototype.flatmap: 1.3.3
+ debug: 3.2.7
+ doctrine: 2.1.0
+ eslint: 9.35.0(jiti@2.5.1)
+ eslint-import-resolver-node: 0.3.9
+ eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1))
+ hasown: 2.0.2
+ is-core-module: 2.16.1
+ is-glob: 4.0.3
+ minimatch: 3.1.2
+ object.fromentries: 2.0.8
+ object.groupby: 1.0.3
+ object.values: 1.2.1
+ semver: 6.3.1
+ string.prototype.trimend: 1.0.9
+ tsconfig-paths: 3.15.0
+ optionalDependencies:
+ '@typescript-eslint/parser': 8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)
+ transitivePeerDependencies:
+ - eslint-import-resolver-typescript
+ - eslint-import-resolver-webpack
+ - supports-color
+
+ eslint-plugin-jsx-a11y@6.10.2(eslint@9.35.0(jiti@2.5.1)):
+ dependencies:
+ aria-query: 5.3.2
+ array-includes: 3.1.9
+ array.prototype.flatmap: 1.3.3
+ ast-types-flow: 0.0.8
+ axe-core: 4.10.3
+ axobject-query: 4.1.0
+ damerau-levenshtein: 1.0.8
+ emoji-regex: 9.2.2
+ eslint: 9.35.0(jiti@2.5.1)
+ hasown: 2.0.2
+ jsx-ast-utils: 3.3.5
+ language-tags: 1.0.9
+ minimatch: 3.1.2
+ object.fromentries: 2.0.8
+ safe-regex-test: 1.1.0
+ string.prototype.includes: 2.0.1
+
+ eslint-plugin-react-hooks@5.2.0(eslint@9.35.0(jiti@2.5.1)):
+ dependencies:
+ eslint: 9.35.0(jiti@2.5.1)
+
+ eslint-plugin-react@7.37.5(eslint@9.35.0(jiti@2.5.1)):
+ dependencies:
+ array-includes: 3.1.9
+ array.prototype.findlast: 1.2.5
+ array.prototype.flatmap: 1.3.3
+ array.prototype.tosorted: 1.1.4
+ doctrine: 2.1.0
+ es-iterator-helpers: 1.2.1
+ eslint: 9.35.0(jiti@2.5.1)
+ estraverse: 5.3.0
+ hasown: 2.0.2
+ jsx-ast-utils: 3.3.5
+ minimatch: 3.1.2
+ object.entries: 1.1.9
+ object.fromentries: 2.0.8
+ object.values: 1.2.1
+ prop-types: 15.8.1
+ resolve: 2.0.0-next.5
+ semver: 6.3.1
+ string.prototype.matchall: 4.0.12
+ string.prototype.repeat: 1.0.0
+
+ eslint-scope@8.4.0:
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+
+ eslint-visitor-keys@3.4.3: {}
+
+ eslint-visitor-keys@4.2.1: {}
+
+ eslint@9.35.0(jiti@2.5.1):
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.0(eslint@9.35.0(jiti@2.5.1))
+ '@eslint-community/regexpp': 4.12.1
+ '@eslint/config-array': 0.21.0
+ '@eslint/config-helpers': 0.3.1
+ '@eslint/core': 0.15.2
+ '@eslint/eslintrc': 3.3.1
+ '@eslint/js': 9.35.0
+ '@eslint/plugin-kit': 0.3.5
+ '@humanfs/node': 0.16.7
+ '@humanwhocodes/module-importer': 1.0.1
+ '@humanwhocodes/retry': 0.4.3
+ '@types/estree': 1.0.8
+ '@types/json-schema': 7.0.15
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.6
+ debug: 4.4.3
+ escape-string-regexp: 4.0.0
+ eslint-scope: 8.4.0
+ eslint-visitor-keys: 4.2.1
+ espree: 10.4.0
+ esquery: 1.6.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 8.0.0
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ ignore: 5.3.2
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ json-stable-stringify-without-jsonify: 1.0.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.2
+ natural-compare: 1.4.0
+ optionator: 0.9.4
+ optionalDependencies:
+ jiti: 2.5.1
+ transitivePeerDependencies:
+ - supports-color
+
+ espree@10.4.0:
+ dependencies:
+ acorn: 8.15.0
+ acorn-jsx: 5.3.2(acorn@8.15.0)
+ eslint-visitor-keys: 4.2.1
+
+ esquery@1.6.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ esrecurse@4.3.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ estraverse@5.3.0: {}
+
+ esutils@2.0.3: {}
+
+ fast-deep-equal@3.1.3: {}
+
+ fast-glob@3.3.1:
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.8
+
+ fast-glob@3.3.3:
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.8
+
+ fast-json-stable-stringify@2.1.0: {}
+
+ fast-levenshtein@2.0.6: {}
+
+ fastq@1.19.1:
+ dependencies:
+ reusify: 1.1.0
+
+ fdir@6.5.0(picomatch@4.0.3):
+ optionalDependencies:
+ picomatch: 4.0.3
+
+ file-entry-cache@8.0.0:
+ dependencies:
+ flat-cache: 4.0.1
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ find-up@5.0.0:
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+
+ flat-cache@4.0.1:
+ dependencies:
+ flatted: 3.3.3
+ keyv: 4.5.4
+
+ flatted@3.3.3: {}
+
+ for-each@0.3.5:
+ dependencies:
+ is-callable: 1.2.7
+
+ fraction.js@4.3.7: {}
+
+ function-bind@1.1.2: {}
+
+ function.prototype.name@1.1.8:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ functions-have-names: 1.2.3
+ hasown: 2.0.2
+ is-callable: 1.2.7
+
+ functions-have-names@1.2.3: {}
+
+ get-intrinsic@1.3.0:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ function-bind: 1.1.2
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ has-symbols: 1.1.0
+ hasown: 2.0.2
+ math-intrinsics: 1.1.0
+
+ get-proto@1.0.1:
+ dependencies:
+ dunder-proto: 1.0.1
+ es-object-atoms: 1.1.1
+
+ get-symbol-description@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+
+ get-tsconfig@4.10.1:
+ dependencies:
+ resolve-pkg-maps: 1.0.0
+
+ glob-parent@5.1.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ glob-parent@6.0.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ globals@14.0.0: {}
+
+ globalthis@1.0.4:
+ dependencies:
+ define-properties: 1.2.1
+ gopd: 1.2.0
+
+ gopd@1.2.0: {}
+
+ graceful-fs@4.2.11: {}
+
+ graphemer@1.4.0: {}
+
+ has-bigints@1.1.0: {}
+
+ has-flag@4.0.0: {}
+
+ has-property-descriptors@1.0.2:
+ dependencies:
+ es-define-property: 1.0.1
+
+ has-proto@1.2.0:
+ dependencies:
+ dunder-proto: 1.0.1
+
+ has-symbols@1.1.0: {}
+
+ has-tostringtag@1.0.2:
+ dependencies:
+ has-symbols: 1.1.0
+
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
+ ignore@5.3.2: {}
+
+ ignore@7.0.5: {}
+
+ import-fresh@3.3.1:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
+ imurmurhash@0.1.4: {}
+
+ internal-slot@1.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ hasown: 2.0.2
+ side-channel: 1.1.0
+
+ is-array-buffer@3.0.5:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
+
+ is-arrayish@0.3.4:
+ optional: true
+
+ is-async-function@2.1.1:
+ dependencies:
+ async-function: 1.0.0
+ call-bound: 1.0.4
+ get-proto: 1.0.1
+ has-tostringtag: 1.0.2
+ safe-regex-test: 1.1.0
+
+ is-bigint@1.1.0:
+ dependencies:
+ has-bigints: 1.1.0
+
+ is-boolean-object@1.2.2:
+ dependencies:
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
+
+ is-bun-module@2.0.0:
+ dependencies:
+ semver: 7.7.2
+
+ is-callable@1.2.7: {}
+
+ is-core-module@2.16.1:
+ dependencies:
+ hasown: 2.0.2
+
+ is-data-view@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
+ is-typed-array: 1.1.15
+
+ is-date-object@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
+
+ is-extglob@2.1.1: {}
+
+ is-finalizationregistry@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+
+ is-generator-function@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ get-proto: 1.0.1
+ has-tostringtag: 1.0.2
+ safe-regex-test: 1.1.0
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-map@2.0.3: {}
+
+ is-negative-zero@2.0.3: {}
+
+ is-number-object@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
+
+ is-number@7.0.0: {}
+
+ is-regex@1.2.1:
+ dependencies:
+ call-bound: 1.0.4
+ gopd: 1.2.0
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
+
+ is-set@2.0.3: {}
+
+ is-shared-array-buffer@1.0.4:
+ dependencies:
+ call-bound: 1.0.4
+
+ is-string@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
+
+ is-symbol@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+ has-symbols: 1.1.0
+ safe-regex-test: 1.1.0
+
+ is-typed-array@1.1.15:
+ dependencies:
+ which-typed-array: 1.1.19
+
+ is-weakmap@2.0.2: {}
+
+ is-weakref@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+
+ is-weakset@2.0.4:
+ dependencies:
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
+
+ isarray@2.0.5: {}
+
+ isexe@2.0.0: {}
+
+ iterator.prototype@1.1.5:
+ dependencies:
+ define-data-property: 1.1.4
+ es-object-atoms: 1.1.1
+ get-intrinsic: 1.3.0
+ get-proto: 1.0.1
+ has-symbols: 1.1.0
+ set-function-name: 2.0.2
+
+ jiti@2.5.1: {}
+
+ js-tokens@4.0.0: {}
+
+ js-yaml@4.1.0:
+ dependencies:
+ argparse: 2.0.1
+
+ json-buffer@3.0.1: {}
+
+ json-schema-traverse@0.4.1: {}
+
+ json-stable-stringify-without-jsonify@1.0.1: {}
+
+ json5@1.0.2:
+ dependencies:
+ minimist: 1.2.8
+
+ jsx-ast-utils@3.3.5:
+ dependencies:
+ array-includes: 3.1.9
+ array.prototype.flat: 1.3.3
+ object.assign: 4.1.7
+ object.values: 1.2.1
+
+ keyv@4.5.4:
+ dependencies:
+ json-buffer: 3.0.1
+
+ language-subtag-registry@0.3.23: {}
+
+ language-tags@1.0.9:
+ dependencies:
+ language-subtag-registry: 0.3.23
+
+ levn@0.4.1:
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+
+ lightningcss-darwin-arm64@1.30.1:
+ optional: true
+
+ lightningcss-darwin-x64@1.30.1:
+ optional: true
+
+ lightningcss-freebsd-x64@1.30.1:
+ optional: true
+
+ lightningcss-linux-arm-gnueabihf@1.30.1:
+ optional: true
+
+ lightningcss-linux-arm64-gnu@1.30.1:
+ optional: true
+
+ lightningcss-linux-arm64-musl@1.30.1:
+ optional: true
+
+ lightningcss-linux-x64-gnu@1.30.1:
+ optional: true
+
+ lightningcss-linux-x64-musl@1.30.1:
+ optional: true
+
+ lightningcss-win32-arm64-msvc@1.30.1:
+ optional: true
+
+ lightningcss-win32-x64-msvc@1.30.1:
+ optional: true
+
+ lightningcss@1.30.1:
+ dependencies:
+ detect-libc: 2.0.4
+ optionalDependencies:
+ lightningcss-darwin-arm64: 1.30.1
+ lightningcss-darwin-x64: 1.30.1
+ lightningcss-freebsd-x64: 1.30.1
+ lightningcss-linux-arm-gnueabihf: 1.30.1
+ lightningcss-linux-arm64-gnu: 1.30.1
+ lightningcss-linux-arm64-musl: 1.30.1
+ lightningcss-linux-x64-gnu: 1.30.1
+ lightningcss-linux-x64-musl: 1.30.1
+ lightningcss-win32-arm64-msvc: 1.30.1
+ lightningcss-win32-x64-msvc: 1.30.1
+
+ locate-path@6.0.0:
+ dependencies:
+ p-locate: 5.0.0
+
+ lodash.castarray@4.4.0: {}
+
+ lodash.isplainobject@4.0.6: {}
+
+ lodash.merge@4.6.2: {}
+
+ loose-envify@1.4.0:
+ dependencies:
+ js-tokens: 4.0.0
+
+ lucide-react@0.544.0(react@19.1.1):
+ dependencies:
+ react: 19.1.1
+
+ magic-string@0.30.19:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ math-intrinsics@1.1.0: {}
+
+ merge2@1.4.1: {}
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
+ mini-svg-data-uri@1.4.4: {}
+
+ minimatch@3.1.2:
+ dependencies:
+ brace-expansion: 1.1.12
+
+ minimatch@9.0.5:
+ dependencies:
+ brace-expansion: 2.0.2
+
+ minimist@1.2.8: {}
+
+ minipass@7.1.2: {}
+
+ minizlib@3.0.2:
+ dependencies:
+ minipass: 7.1.2
+
+ mkdirp@3.0.1: {}
+
+ ms@2.1.3: {}
+
+ nanoid@3.3.11: {}
+
+ napi-postinstall@0.3.3: {}
+
+ natural-compare@1.4.0: {}
+
+ next@15.5.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
+ dependencies:
+ '@next/env': 15.5.3
+ '@swc/helpers': 0.5.15
+ caniuse-lite: 1.0.30001741
+ postcss: 8.4.31
+ react: 19.1.1
+ react-dom: 19.1.1(react@19.1.1)
+ styled-jsx: 5.1.6(react@19.1.1)
+ optionalDependencies:
+ '@next/swc-darwin-arm64': 15.5.3
+ '@next/swc-darwin-x64': 15.5.3
+ '@next/swc-linux-arm64-gnu': 15.5.3
+ '@next/swc-linux-arm64-musl': 15.5.3
+ '@next/swc-linux-x64-gnu': 15.5.3
+ '@next/swc-linux-x64-musl': 15.5.3
+ '@next/swc-win32-arm64-msvc': 15.5.3
+ '@next/swc-win32-x64-msvc': 15.5.3
+ sharp: 0.34.3
+ transitivePeerDependencies:
+ - '@babel/core'
+ - babel-plugin-macros
+
+ node-releases@2.0.21: {}
+
+ normalize-range@0.1.2: {}
+
+ object-assign@4.1.1: {}
+
+ object-inspect@1.13.4: {}
+
+ object-keys@1.1.1: {}
+
+ object.assign@4.1.7:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+ has-symbols: 1.1.0
+ object-keys: 1.1.1
+
+ object.entries@1.1.9:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+
+ object.fromentries@2.0.8:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-object-atoms: 1.1.1
+
+ object.groupby@1.0.3:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+
+ object.values@1.2.1:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+
+ optionator@0.9.4:
+ dependencies:
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ word-wrap: 1.2.5
+
+ own-keys@1.0.1:
+ dependencies:
+ get-intrinsic: 1.3.0
+ object-keys: 1.1.1
+ safe-push-apply: 1.0.0
+
+ p-limit@3.1.0:
+ dependencies:
+ yocto-queue: 0.1.0
+
+ p-locate@5.0.0:
+ dependencies:
+ p-limit: 3.1.0
+
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
+ path-exists@4.0.0: {}
+
+ path-key@3.1.1: {}
+
+ path-parse@1.0.7: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ picomatch@4.0.3: {}
+
+ possible-typed-array-names@1.1.0: {}
+
+ postcss-selector-parser@6.0.10:
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+
+ postcss-value-parser@4.2.0: {}
+
+ postcss@8.4.31:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ postcss@8.5.6:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ prelude-ls@1.2.1: {}
+
+ prop-types@15.8.1:
+ dependencies:
+ loose-envify: 1.4.0
+ object-assign: 4.1.1
+ react-is: 16.13.1
+
+ punycode@2.3.1: {}
+
+ queue-microtask@1.2.3: {}
+
+ react-dom@19.1.1(react@19.1.1):
+ dependencies:
+ react: 19.1.1
+ scheduler: 0.26.0
+
+ react-is@16.13.1: {}
+
+ react@19.1.1: {}
+
+ reflect.getprototypeof@1.0.10:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ get-intrinsic: 1.3.0
+ get-proto: 1.0.1
+ which-builtin-type: 1.2.1
+
+ regexp.prototype.flags@1.5.4:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-errors: 1.3.0
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ set-function-name: 2.0.2
+
+ resolve-from@4.0.0: {}
+
+ resolve-pkg-maps@1.0.0: {}
+
+ resolve@1.22.10:
+ dependencies:
+ is-core-module: 2.16.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
+ resolve@2.0.0-next.5:
+ dependencies:
+ is-core-module: 2.16.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
+ reusify@1.1.0: {}
+
+ run-parallel@1.2.0:
+ dependencies:
+ queue-microtask: 1.2.3
+
+ safe-array-concat@1.1.3:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
+ has-symbols: 1.1.0
+ isarray: 2.0.5
+
+ safe-push-apply@1.0.0:
+ dependencies:
+ es-errors: 1.3.0
+ isarray: 2.0.5
+
+ safe-regex-test@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-regex: 1.2.1
+
+ scheduler@0.26.0: {}
+
+ semver@6.3.1: {}
+
+ semver@7.7.2: {}
+
+ set-function-length@1.2.2:
+ dependencies:
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.3.0
+ gopd: 1.2.0
+ has-property-descriptors: 1.0.2
+
+ set-function-name@2.0.2:
+ dependencies:
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ functions-have-names: 1.2.3
+ has-property-descriptors: 1.0.2
+
+ set-proto@1.0.0:
+ dependencies:
+ dunder-proto: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+
+ sharp@0.34.3:
+ dependencies:
+ color: 4.2.3
+ detect-libc: 2.0.4
+ semver: 7.7.2
+ optionalDependencies:
+ '@img/sharp-darwin-arm64': 0.34.3
+ '@img/sharp-darwin-x64': 0.34.3
+ '@img/sharp-libvips-darwin-arm64': 1.2.0
+ '@img/sharp-libvips-darwin-x64': 1.2.0
+ '@img/sharp-libvips-linux-arm': 1.2.0
+ '@img/sharp-libvips-linux-arm64': 1.2.0
+ '@img/sharp-libvips-linux-ppc64': 1.2.0
+ '@img/sharp-libvips-linux-s390x': 1.2.0
+ '@img/sharp-libvips-linux-x64': 1.2.0
+ '@img/sharp-libvips-linuxmusl-arm64': 1.2.0
+ '@img/sharp-libvips-linuxmusl-x64': 1.2.0
+ '@img/sharp-linux-arm': 0.34.3
+ '@img/sharp-linux-arm64': 0.34.3
+ '@img/sharp-linux-ppc64': 0.34.3
+ '@img/sharp-linux-s390x': 0.34.3
+ '@img/sharp-linux-x64': 0.34.3
+ '@img/sharp-linuxmusl-arm64': 0.34.3
+ '@img/sharp-linuxmusl-x64': 0.34.3
+ '@img/sharp-wasm32': 0.34.3
+ '@img/sharp-win32-arm64': 0.34.3
+ '@img/sharp-win32-ia32': 0.34.3
+ '@img/sharp-win32-x64': 0.34.3
+ optional: true
+
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
+
+ side-channel-list@1.0.0:
+ dependencies:
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
+
+ side-channel-map@1.0.1:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
+
+ side-channel-weakmap@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-map: 1.0.1
+
+ side-channel@1.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-list: 1.0.0
+ side-channel-map: 1.0.1
+ side-channel-weakmap: 1.0.2
+
+ simple-swizzle@0.2.4:
+ dependencies:
+ is-arrayish: 0.3.4
+ optional: true
+
+ source-map-js@1.2.1: {}
+
+ stable-hash@0.0.5: {}
+
+ stop-iteration-iterator@1.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ internal-slot: 1.1.0
+
+ string.prototype.includes@2.0.1:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+
+ string.prototype.matchall@4.0.12:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ get-intrinsic: 1.3.0
+ gopd: 1.2.0
+ has-symbols: 1.1.0
+ internal-slot: 1.1.0
+ regexp.prototype.flags: 1.5.4
+ set-function-name: 2.0.2
+ side-channel: 1.1.0
+
+ string.prototype.repeat@1.0.0:
+ dependencies:
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+
+ string.prototype.trim@1.2.10:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-data-property: 1.1.4
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-object-atoms: 1.1.1
+ has-property-descriptors: 1.0.2
+
+ string.prototype.trimend@1.0.9:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+
+ string.prototype.trimstart@1.0.8:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+
+ strip-bom@3.0.0: {}
+
+ strip-json-comments@3.1.1: {}
+
+ styled-jsx@5.1.6(react@19.1.1):
+ dependencies:
+ client-only: 0.0.1
+ react: 19.1.1
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ supports-preserve-symlinks-flag@1.0.0: {}
+
+ tailwindcss@4.1.13: {}
+
+ tapable@2.2.3: {}
+
+ tar@7.4.3:
+ dependencies:
+ '@isaacs/fs-minipass': 4.0.1
+ chownr: 3.0.0
+ minipass: 7.1.2
+ minizlib: 3.0.2
+ mkdirp: 3.0.1
+ yallist: 5.0.0
+
+ tinyglobby@0.2.15:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ ts-api-utils@2.1.0(typescript@5.9.2):
+ dependencies:
+ typescript: 5.9.2
+
+ tsconfig-paths@3.15.0:
+ dependencies:
+ '@types/json5': 0.0.29
+ json5: 1.0.2
+ minimist: 1.2.8
+ strip-bom: 3.0.0
+
+ tslib@2.8.1: {}
+
+ type-check@0.4.0:
+ dependencies:
+ prelude-ls: 1.2.1
+
+ typed-array-buffer@1.0.3:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-typed-array: 1.1.15
+
+ typed-array-byte-length@1.0.3:
+ dependencies:
+ call-bind: 1.0.8
+ for-each: 0.3.5
+ gopd: 1.2.0
+ has-proto: 1.2.0
+ is-typed-array: 1.1.15
+
+ typed-array-byte-offset@1.0.4:
+ dependencies:
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.8
+ for-each: 0.3.5
+ gopd: 1.2.0
+ has-proto: 1.2.0
+ is-typed-array: 1.1.15
+ reflect.getprototypeof: 1.0.10
+
+ typed-array-length@1.0.7:
+ dependencies:
+ call-bind: 1.0.8
+ for-each: 0.3.5
+ gopd: 1.2.0
+ is-typed-array: 1.1.15
+ possible-typed-array-names: 1.1.0
+ reflect.getprototypeof: 1.0.10
+
+ typescript@5.9.2: {}
+
+ unbox-primitive@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ has-bigints: 1.1.0
+ has-symbols: 1.1.0
+ which-boxed-primitive: 1.1.1
+
+ undici-types@7.10.0: {}
+
+ unrs-resolver@1.11.1:
+ dependencies:
+ napi-postinstall: 0.3.3
+ optionalDependencies:
+ '@unrs/resolver-binding-android-arm-eabi': 1.11.1
+ '@unrs/resolver-binding-android-arm64': 1.11.1
+ '@unrs/resolver-binding-darwin-arm64': 1.11.1
+ '@unrs/resolver-binding-darwin-x64': 1.11.1
+ '@unrs/resolver-binding-freebsd-x64': 1.11.1
+ '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1
+ '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1
+ '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1
+ '@unrs/resolver-binding-linux-arm64-musl': 1.11.1
+ '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1
+ '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1
+ '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1
+ '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1
+ '@unrs/resolver-binding-linux-x64-gnu': 1.11.1
+ '@unrs/resolver-binding-linux-x64-musl': 1.11.1
+ '@unrs/resolver-binding-wasm32-wasi': 1.11.1
+ '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1
+ '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1
+ '@unrs/resolver-binding-win32-x64-msvc': 1.11.1
+
+ update-browserslist-db@1.1.3(browserslist@4.26.0):
+ dependencies:
+ browserslist: 4.26.0
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ uri-js@4.4.1:
+ dependencies:
+ punycode: 2.3.1
+
+ util-deprecate@1.0.2: {}
+
+ which-boxed-primitive@1.1.1:
+ dependencies:
+ is-bigint: 1.1.0
+ is-boolean-object: 1.2.2
+ is-number-object: 1.1.1
+ is-string: 1.1.1
+ is-symbol: 1.1.1
+
+ which-builtin-type@1.2.1:
+ dependencies:
+ call-bound: 1.0.4
+ function.prototype.name: 1.1.8
+ has-tostringtag: 1.0.2
+ is-async-function: 2.1.1
+ is-date-object: 1.1.0
+ is-finalizationregistry: 1.1.1
+ is-generator-function: 1.1.0
+ is-regex: 1.2.1
+ is-weakref: 1.1.1
+ isarray: 2.0.5
+ which-boxed-primitive: 1.1.1
+ which-collection: 1.0.2
+ which-typed-array: 1.1.19
+
+ which-collection@1.0.2:
+ dependencies:
+ is-map: 2.0.3
+ is-set: 2.0.3
+ is-weakmap: 2.0.2
+ is-weakset: 2.0.4
+
+ which-typed-array@1.1.19:
+ dependencies:
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ for-each: 0.3.5
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ has-tostringtag: 1.0.2
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
+
+ word-wrap@1.2.5: {}
+
+ yallist@5.0.0: {}
+
+ yocto-queue@0.1.0: {}
diff --git a/banquise-website/postcss.config.js b/banquise-website/postcss.config.js
index 2e7af2b..fb8e0e3 100644
--- a/banquise-website/postcss.config.js
+++ b/banquise-website/postcss.config.js
@@ -1,6 +1,7 @@
export default {
plugins: {
- tailwindcss: {},
+ '@tailwindcss/postcss': {},
autoprefixer: {},
},
}
+
diff --git a/banquise-website/public/assets/Gitea_Logo.png b/banquise-website/public/assets/Gitea_Logo.png
new file mode 100644
index 0000000..75ea7df
Binary files /dev/null and b/banquise-website/public/assets/Gitea_Logo.png differ
diff --git a/banquise-website/src/assets/banquise.png b/banquise-website/public/assets/banquise.png
similarity index 100%
rename from banquise-website/src/assets/banquise.png
rename to banquise-website/public/assets/banquise.png
diff --git a/banquise-website/src/assets/banquise_server.svg b/banquise-website/public/assets/banquise_server.svg
similarity index 100%
rename from banquise-website/src/assets/banquise_server.svg
rename to banquise-website/public/assets/banquise_server.svg
diff --git a/banquise-website/src/assets/iceberg.png b/banquise-website/public/assets/iceberg.png
similarity index 100%
rename from banquise-website/src/assets/iceberg.png
rename to banquise-website/public/assets/iceberg.png
diff --git a/banquise-website/public/assets/opencloud_logo_white.png b/banquise-website/public/assets/opencloud_logo_white.png
new file mode 100644
index 0000000..699e164
Binary files /dev/null and b/banquise-website/public/assets/opencloud_logo_white.png differ
diff --git a/banquise-website/public/assets/pelican.png b/banquise-website/public/assets/pelican.png
new file mode 100644
index 0000000..e3177f2
Binary files /dev/null and b/banquise-website/public/assets/pelican.png differ
diff --git a/banquise-website/public/assets/wikijs.png b/banquise-website/public/assets/wikijs.png
new file mode 100644
index 0000000..59cdccb
Binary files /dev/null and b/banquise-website/public/assets/wikijs.png differ
diff --git a/banquise-website/src/App.css b/banquise-website/src/App.css
deleted file mode 100644
index b797a0b..0000000
--- a/banquise-website/src/App.css
+++ /dev/null
@@ -1 +0,0 @@
-/* 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
deleted file mode 100644
index e6ea4ea..0000000
--- a/banquise-website/src/App.tsx
+++ /dev/null
@@ -1,106 +0,0 @@
-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';
-
-// 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
deleted file mode 100644
index 0072ea6..0000000
--- a/banquise-website/src/components/layout/Footer.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-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
deleted file mode 100644
index a233ef8..0000000
--- a/banquise-website/src/components/layout/MobileMenu.tsx
+++ /dev/null
@@ -1,154 +0,0 @@
-import React, { useEffect } from 'react';
-import banquiseServer from '../../assets/banquise_server.svg'
-import { URLS, SITE_CONFIG } from '../../config/constants';
-import { commonStyles } from '../../styles/components';
-
-interface MobileMenuProps {
- isOpen: boolean;
- onClose: () => void;
-}
-
-export const MobileMenu: React.FC = ({ isOpen, onClose }) => {
- useEffect(() => {
- if (isOpen) {
- document.body.style.overflow = 'hidden';
- } else {
- document.body.style.overflow = 'unset';
- }
-
- return () => {
- document.body.style.overflow = 'unset';
- };
- }, [isOpen]);
-
- return (
-
- {/* Overlay */}
-
-
- {/* Menu mobile */}
-
-
- {/* Header */}
-
-
-
-
-
-
-
-
- {SITE_CONFIG.name}
-
-
Menu Navigation
-
-
-
-
-
-
-
-
-
-
- {/* Navigation */}
-
-
- {/* Navigation Links */}
-
-
- {/* CTA Button */}
-
-
-
- {/* Footer */}
-
-
-
- © 2024 {SITE_CONFIG.name}
-
-
-
-
- {/* Effet glassmorphism */}
-
-
-
- );
-};
diff --git a/banquise-website/src/components/layout/Navigation.tsx b/banquise-website/src/components/layout/Navigation.tsx
deleted file mode 100644
index 70935b2..0000000
--- a/banquise-website/src/components/layout/Navigation.tsx
+++ /dev/null
@@ -1,147 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { MobileMenu } from './MobileMenu';
-import banquiseServer from '/src/assets/banquise_server.svg'
-import { URLS, SITE_CONFIG } from '../../config/constants';
-import { commonStyles } from '../../styles/components';
-
-export const Navigation: React.FC = () => {
- const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
- const [scrolled, setScrolled] = useState(false);
-
- useEffect(() => {
- const handleScroll = () => {
- const isScrolled = window.scrollY > 20;
- setScrolled(isScrolled);
- };
-
- window.addEventListener('scroll', handleScroll);
- return () => window.removeEventListener('scroll', handleScroll);
- }, []);
-
- useEffect(() => {
- const handleResize = () => {
- if (window.innerWidth >= 768) {
- setMobileMenuOpen(false);
- }
- };
-
- window.addEventListener('resize', handleResize);
- return () => window.removeEventListener('resize', handleResize);
- }, []);
-
- return (
- <>
-
-
-
-
- {/* Logo section */}
-
-
-
-
-
-
-
- {SITE_CONFIG.name}
-
-
- {SITE_CONFIG.tagline}
-
-
-
-
- {/* Navigation links desktop */}
-
-
- {/* Action buttons desktop */}
-
-
- {/* Mobile menu button */}
-
setMobileMenuOpen(!mobileMenuOpen)}
- aria-label={mobileMenuOpen ? "Fermer le menu" : "Ouvrir le menu"}
- aria-expanded={mobileMenuOpen}
- >
-
-
-
-
-
-
-
-
-
- {/* Glassmorphism effect bar */}
-
-
-
- {/* Spacer pour compenser la navbar fixed */}
-
-
- {/* Menu mobile */}
- setMobileMenuOpen(false)}
- />
- >
- );
-};
diff --git a/banquise-website/src/components/sections/AboutSection.tsx b/banquise-website/src/components/sections/AboutSection.tsx
deleted file mode 100644
index e71693f..0000000
--- a/banquise-website/src/components/sections/AboutSection.tsx
+++ /dev/null
@@ -1,124 +0,0 @@
-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
deleted file mode 100644
index b6b8eac..0000000
--- a/banquise-website/src/components/sections/HeroSection.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import React from 'react';
-import banquiseServer from '/src/assets/banquise_server.svg'
-
-export const HeroSection: React.FC = () => (
-
-
-
-
-
-
- Bienvenue sur La Banquise
-
-
-
- Association d'hébergement et lab réseau pour tous les étudiants et associations de l'EPITA !
-
-
-
- Découvrir nos services
- →
-
-
-);
diff --git a/banquise-website/src/components/sections/ServicesSection.tsx b/banquise-website/src/components/sections/ServicesSection.tsx
deleted file mode 100644
index ad58cef..0000000
--- a/banquise-website/src/components/sections/ServicesSection.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-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
deleted file mode 100644
index 417c98f..0000000
--- a/banquise-website/src/components/sections/TechFeaturesSection.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-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
deleted file mode 100644
index 2f7fd4d..0000000
--- a/banquise-website/src/components/ui/AccordionItem.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from 'react';
-
-// Définir l'interface localement :
-interface AccordionItemProps {
- title: string;
- children: React.ReactNode;
- isOpen: boolean;
- onToggle: () => void;
-}
-
-export const AccordionItem: React.FC = ({ title, children, isOpen, onToggle }) => (
-
-
- {title}
-
- ▼
-
-
-
-
-);
diff --git a/banquise-website/src/components/ui/ParallaxBackground.tsx b/banquise-website/src/components/ui/ParallaxBackground.tsx
deleted file mode 100644
index b8e33b5..0000000
--- a/banquise-website/src/components/ui/ParallaxBackground.tsx
+++ /dev/null
@@ -1,146 +0,0 @@
-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
deleted file mode 100644
index 8ed8158..0000000
--- a/banquise-website/src/components/ui/Popup.tsx
+++ /dev/null
@@ -1,141 +0,0 @@
-import React, { useEffect } from 'react';
-import { URLS } from '../../config/constants';
-
-interface Service {
- name: string;
- url: string;
- image: string;
- icon: string;
- description: string;
- features: string[];
-}
-
-interface PopupProps {
- service: Service;
- onClose: () => void;
-}
-
-export const Popup: React.FC = ({ service, onClose }) => {
- // Empêcher le scroll du body quand la popup est ouverte
- useEffect(() => {
- document.body.style.overflow = 'hidden';
-
- return () => {
- document.body.style.overflow = 'unset';
- };
- }, []);
-
- return (
-
-
-
- {/* Bouton de fermeture fixe au-dessus du contenu */}
-
-
- ×
-
-
-
- {/* Contenu avec scroll vertical uniquement */}
-
- {/* Header */}
-
-
-
- {service.icon}
-
-
-
- {service.name}
-
-
- Service d'hébergement professionnel
-
-
- Haute disponibilité
- Open Source
- Communautaire
-
-
-
-
-
- {/* Content - Forcer le fond blanc */}
-
- {/* Description */}
-
- 📋
- Description détaillée
-
-
-
- {service.description}
-
-
-
-
- ✓
-
-
-
99.9% Uptime
-
Disponibilité garantie
-
-
-
-
- 🔒
-
-
-
Sécurisé
-
SSL & Backups
-
-
-
-
-
- {/* Fonctionnalités */}
-
- ⚡
- Fonctionnalités principales
-
-
- {service.features.map((feature, index) => (
-
- ))}
-
-
- {/* Call to action */}
-
-
-
-
- {/* Decorative elements */}
-
-
-
-
- );
-};
diff --git a/banquise-website/src/components/ui/ScrollToTopButton.tsx b/banquise-website/src/components/ui/ScrollToTopButton.tsx
deleted file mode 100644
index a05463b..0000000
--- a/banquise-website/src/components/ui/ScrollToTopButton.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import React, { useState, useEffect } from 'react';
-
-export const ScrollToTopButton: React.FC = () => {
- const [isVisible, setIsVisible] = useState(false);
-
- useEffect(() => {
- const toggleVisibility = () => {
- // Afficher le bouton après avoir scrollé 300px
- setIsVisible(window.scrollY > 300);
- };
-
- window.addEventListener('scroll', toggleVisibility);
- return () => window.removeEventListener('scroll', toggleVisibility);
- }, []);
-
- const scrollToTop = () => {
- window.scrollTo({
- top: 0,
- behavior: 'smooth'
- });
- };
-
- return (
-
-
-
-
-
- {/* Effet de lueur au hover */}
-
-
- );
-};
diff --git a/banquise-website/src/index.css b/banquise-website/src/index.css
deleted file mode 100644
index ca06f66..0000000
--- a/banquise-website/src/index.css
+++ /dev/null
@@ -1,185 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-/* Variables CSS pour les polices */
-:root {
- --font-heading: 'Dela Gothic One', sans-serif;
- --font-body: 'Roboto', sans-serif;
-}
-
-/* Parallax animations */
-@keyframes parallax-slow {
- 0% { transform: translateY(0px); }
- 100% { transform: translateY(-50px); }
-}
-
-@keyframes parallax-medium {
- 0% { transform: translateY(0px); }
- 100% { transform: translateY(-80px); }
-}
-
-@keyframes parallax-fast {
- 0% { transform: translateY(0px); }
- 100% { transform: translateY(-120px); }
-}
-
-@keyframes parallax-very-slow {
- 0% { transform: translateY(0px); }
- 100% { transform: translateY(-20px); }
-}
-
-/* Floating animations with different speeds */
-@keyframes float-slow {
- 0%, 100% { transform: translateY(0px) rotate(0deg); }
- 50% { transform: translateY(-20px) rotate(5deg); }
-}
-
-@keyframes float-medium {
- 0%, 100% { transform: translateY(0px) rotate(0deg); }
- 50% { transform: translateY(-15px) rotate(-3deg); }
-}
-
-@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 {
- 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;
-}
diff --git a/banquise-website/src/main.tsx b/banquise-website/src/main.tsx
deleted file mode 100644
index e3f1654..0000000
--- a/banquise-website/src/main.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { StrictMode } from 'react'
-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
deleted file mode 100644
index 48fcabf..0000000
--- a/banquise-website/src/styles/components.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-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
deleted file mode 100644
index 3c8eb7a..0000000
--- a/banquise-website/src/types/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-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/src/vite-env.d.ts b/banquise-website/src/vite-env.d.ts
deleted file mode 100644
index 11f02fe..0000000
--- a/banquise-website/src/vite-env.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-///
diff --git a/banquise-website/tailwind.config.js b/banquise-website/tailwind.config.js
deleted file mode 100644
index 724fe8a..0000000
--- a/banquise-website/tailwind.config.js
+++ /dev/null
@@ -1,119 +0,0 @@
-/** @type {import('tailwindcss').Config} */
-export default {
- content: [
- "./index.html",
- "./src/**/*.{js,ts,jsx,tsx}",
- ],
- theme: {
- extend: {
- colors: {
- banquise: {
- blue: '#40B4FF',
- 'blue-dark': '#1F5D89',
- 'blue-light': '#69B7E2',
- 'blue-lightest': '#A5F0FF',
- gray: '#F6F6F6',
- }
- },
- fontFamily: {
- 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: [
- require('@tailwindcss/forms'),
- require('@tailwindcss/typography'),
- ],
-}
diff --git a/banquise-website/tsconfig.app.json b/banquise-website/tsconfig.app.json
deleted file mode 100644
index c9ccbd4..0000000
--- a/banquise-website/tsconfig.app.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "compilerOptions": {
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
- "target": "ES2020",
- "useDefineForClassFields": true,
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
- "module": "ESNext",
- "skipLibCheck": true,
-
- /* Bundler mode */
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "verbatimModuleSyntax": true,
- "moduleDetection": "force",
- "noEmit": true,
- "jsx": "react-jsx",
-
- /* Linting */
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "erasableSyntaxOnly": true,
- "noFallthroughCasesInSwitch": true,
- "noUncheckedSideEffectImports": true
- },
- "include": ["src"]
-}
diff --git a/banquise-website/tsconfig.json b/banquise-website/tsconfig.json
index 1ffef60..b021bc6 100644
--- a/banquise-website/tsconfig.json
+++ b/banquise-website/tsconfig.json
@@ -1,7 +1,41 @@
{
- "files": [],
- "references": [
- { "path": "./tsconfig.app.json" },
- { "path": "./tsconfig.node.json" }
+ "compilerOptions": {
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "baseUrl": ".",
+ "paths": {
+ "@/*": [
+ "./*"
+ ]
+ },
+ "target": "ES2017"
+ },
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
]
}
diff --git a/banquise-website/tsconfig.node.json b/banquise-website/tsconfig.node.json
deleted file mode 100644
index 9728af2..0000000
--- a/banquise-website/tsconfig.node.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "compilerOptions": {
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
- "target": "ES2022",
- "lib": ["ES2023"],
- "module": "ESNext",
- "skipLibCheck": true,
-
- /* Bundler mode */
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "verbatimModuleSyntax": true,
- "moduleDetection": "force",
- "noEmit": true,
-
- /* Linting */
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "erasableSyntaxOnly": true,
- "noFallthroughCasesInSwitch": true,
- "noUncheckedSideEffectImports": true
- },
- "include": ["vite.config.ts"]
-}
diff --git a/banquise-website/types/i18n.ts b/banquise-website/types/i18n.ts
new file mode 100644
index 0000000..eaff2e8
--- /dev/null
+++ b/banquise-website/types/i18n.ts
@@ -0,0 +1,134 @@
+import type { Service } from './service';
+
+export interface Translation {
+ services: Service[];
+ hero: {
+ title: string;
+ subtitle: string;
+ cta: string;
+ };
+ navigation: {
+ home: string;
+ services: string;
+ about: string;
+ contact: string;
+ };
+ common: {
+ discoverFeatures: string;
+ close: string;
+ loading: string;
+ learnMore: string;
+ backToHome: string;
+ discoverOffer: string;
+ learnMoreAboutUs: string;
+ sendEmail: string;
+ login: string;
+ joinCommunity: string;
+ backToTop: string;
+ };
+ user: {
+ profile: string;
+ logout: string;
+ groups: string;
+ userMenu: string;
+ connecting: string;
+ authError: string;
+ };
+ about: {
+ title: string;
+ subtitle: string;
+ faqTitle: string;
+ mission: {
+ title: string;
+ description1: string;
+ description2: string;
+ tags: {
+ collaboration: string;
+ innovation: string;
+ accessibility: string;
+ };
+ };
+ services: {
+ title: string;
+ wiki: {
+ title: string;
+ description: string;
+ };
+ gitea: {
+ title: string;
+ description: string;
+ };
+ panel: {
+ title: string;
+ description: string;
+ };
+ pelican: {
+ title: string;
+ description: string;
+ };
+ intranet: {
+ title: string;
+ description: string;
+ };
+ mails: {
+ title: string;
+ description: string;
+ };
+ opencloud: {
+ title: string;
+ description: string;
+ };
+ note: string;
+ };
+ community: {
+ title: string;
+ description: string;
+ howToJoin: string;
+ steps: {
+ step1: string;
+ step2: string;
+ step3: string;
+ };
+ joinDiscord: string;
+ };
+ };
+ sections: {
+ ourServices: string;
+ };
+ footer: {
+ description: string;
+ ourServices: string;
+ community: string;
+ joinAssociation: string;
+ joinDescription: string;
+ joinNow: string;
+ gamingPanel: string;
+ madeWith: string;
+ by: string;
+ copyright: string;
+ };
+ infrastructure: {
+ title: string;
+ subtitle: string;
+ features: {
+ performance: {
+ title: string;
+ description: string;
+ };
+ storage: {
+ title: string;
+ description: string;
+ };
+ network: {
+ title: string;
+ description: string;
+ };
+ security: {
+ title: string;
+ description: string;
+ };
+ };
+ };
+}
+
+export type Language = 'fr' | 'en'; //| 'es' | 'de';
diff --git a/banquise-website/types/index.ts b/banquise-website/types/index.ts
new file mode 100644
index 0000000..5c74b7c
--- /dev/null
+++ b/banquise-website/types/index.ts
@@ -0,0 +1,48 @@
+// Re-export types from their specific modules
+export type { Service } from './service';
+export type { Language, Translation } from './i18n';
+
+// Types communs pour les composants UI
+export interface AccordionItemProps {
+ title: React.ReactNode;
+ children: React.ReactNode;
+ isOpen: boolean;
+ onToggle: () => void;
+}
+
+// Types pour les hooks communs
+export interface UseModalReturn {
+ data: T | null;
+ open: (data: T) => void;
+ close: () => void;
+ isOpen: boolean;
+}
+
+export interface UseToggleReturn {
+ state: boolean;
+ toggle: () => void;
+ setTrue: () => void;
+ setFalse: () => void;
+ setState: (state: boolean) => void;
+}
+
+// Types pour les composants de navigation
+export interface NavigationHandler {
+ (sectionId: string): void;
+}
+
+// Classes CSS communes
+export type CommonClassKey =
+ | 'transition'
+ | 'transitionFast'
+ | 'hoverLift'
+ | 'hoverScale'
+ | 'buttonBase'
+ | 'navLink'
+ | 'cardBase'
+ | 'cardHover'
+ | 'mobileMenuItem';
+
+// Variants pour les boutons optimisés
+export type ButtonVariant = 'primary' | 'discord' | 'auth' | 'secondary' | 'ghost' | 'outline';
+export type ButtonSize = 'sm' | 'md' | 'lg';
diff --git a/banquise-website/types/service.ts b/banquise-website/types/service.ts
new file mode 100644
index 0000000..7b9b512
--- /dev/null
+++ b/banquise-website/types/service.ts
@@ -0,0 +1,13 @@
+import type { StaticImageData } from 'next/image'
+import type { LucideIcon } from 'lucide-react'
+
+export interface Service {
+ name: string;
+ url: string;
+ image: string | StaticImageData;
+ icon: string;
+ iconType: 'image' | 'lucide';
+ lucideIcon?: LucideIcon;
+ description: string;
+ features: string[];
+}
diff --git a/banquise-website/vite.config.ts b/banquise-website/vite.config.ts
deleted file mode 100644
index 350511a..0000000
--- a/banquise-website/vite.config.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
-import viteCompression from 'vite-plugin-compression'
-
-// https://vitejs.dev/config/
-export default defineConfig({
- plugins: [
- react(),
- viteCompression({
- verbose: false,
- algorithm: 'gzip',
- ext: '.gz',
- }),
- ],
- build: {
- minify: 'esbuild',
- cssMinify: true,
- rollupOptions: {
- output: {
- manualChunks: {
- react: ['react', 'react-dom'],
- router: ['react-router-dom'],
- },
- },
- },
- },
-})
diff --git a/shell.nix b/shell.nix
deleted file mode 100644
index e63a99a..0000000
--- a/shell.nix
+++ /dev/null
@@ -1,15 +0,0 @@
-{ pkgs ? import {} }:
-
-pkgs.mkShell {
- buildInputs = [
- pkgs.nodejs_24
- pkgs.nodePackages.tailwindcss
- pkgs.nodePackages.postcss
- pkgs.nodePackages.autoprefixer
- ];
-
- shellHook = ''
- echo "✅ Environnement Node.js avec Tailwind, PostCSS et Autoprefixer prêt !"
- '';
-}
-