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 */} +
+ ); +} 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 ( + + ); +}; 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.name} + ) : service.lucideIcon ? ( + + ) : ( + {service.icon} + )} +
+ + {/* 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 */} + + + {/* Popup Menu */} + {isOpen && ( +
+ {/* Header avec informations utilisateur */} +
+
+ {`Avatar +
+

+ {user.name} +

+

+ {user.email} +

+
+
+
+ + {/* Groupes utilisateur (si disponibles) */} + {user.groups && user.groups.length > 0 && ( +
+

{t.user.groups}

+
+ {user.groups.map((group, index) => ( + + {group} + + ))} +
+
+ )} + + {/* Actions */} +
+ +
+
+ )} + + +
+ ); +}; \ 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 ( +
+
+ {/* Contenu principal du footer */} +
+ + {/* Marque et description */} +
+
+
+ B +
+ + {SITE_CONFIG.name} + +
+

+ {t.footer.description} +

+ {/* Réseaux sociaux */} +
+ + + + + + +
+
+ + {/* Liens rapides services */} +
+

{t.footer.ourServices}

+
+ + Wiki + + + Gitea + + + {t.footer.gamingPanel} + + + OpenCloud + +
+
+ + {/* Informations communauté */} +
+

{t.footer.community}

+
+

{t.footer.joinAssociation}

+

+ {t.footer.joinDescription} +

+ + + {t.footer.joinNow} + +
+
+
+ + {/* Barre du bas */} +
+

+ © 2025 {SITE_CONFIG.name}. {t.footer.copyright} +

+
+ + {t.footer.madeWith} + + {t.footer.by} + +
+ EPITA 2025 +
+
+
+
+ ); +}; 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 */} + + + {/* 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 */} +
+ {SITE_CONFIG.name} +
+
+ + {/* 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 ( + + ); +}; 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 ( + + ); +}; 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 */} +
+
+
+ +
+ {translations.title} +
+
+
+ + {/* 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 */} +
+ +
+
{title}
+ + ▼ + +
+
+
+ {children} +
+
+
+); 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 }) => ( +
+
+ +
+ {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 ( + + + + ); + } + + return ( + + ); +}; + +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 ( + {alt} + ); + } + + 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 */} + + + {/* Dropdown Menu */} + {isOpen && ( +
+ {availableLanguages.map((lang) => { + const config = languageConfig[lang]; + const isSelected = lang === currentLanguage; + + return ( + + ); + })} +
+ )} +
+ ); +}; 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.name} + ) : 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 */} +
+ + + Accéder à {service.name} + + +

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

+
+
+
+ + {/* 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 +}) => ( +
+
+ +
+
+
{title}
+
{subtitle}
+
+
+); + +interface FeatureItemProps { + feature: string; + index: number; +} + +export const FeatureItem: React.FC = ({ feature, index }) => ( +
+
+
+
+ {feature} +
+); + +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 ( + + ); +}; 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 */} -
-
-
-
- Logo -
-
- - {SITE_CONFIG.name} - -

Menu Navigation

-
-
- - -
- - {/* Navigation */} - - - {/* Footer */} -
-
-

- © 2024 {SITE_CONFIG.name} -

-
-
- - {/* Effet glassmorphism */} -
-
-
- ); -}; diff --git a/banquise-website/src/components/layout/Navigation.tsx b/banquise-website/src/components/layout/Navigation.tsx 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 ( - <> - - - {/* 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 = () => ( -
-
- Logo La Banquise -
- -

- Bienvenue sur La Banquise -

- -

- Association d'hébergement et lab réseau pour tous les étudiants et associations de l'EPITA ! -

- - - Découvrir nos services - - -
-); diff --git a/banquise-website/src/components/sections/ServicesSection.tsx b/banquise-website/src/components/sections/ServicesSection.tsx 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} - - ▼ - -
-
-
- {children} -
-
-
-); 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) => ( -
-
-
-
- {feature} -
- ))} -
- - {/* Call to action */} -
- - 🚀 - Accéder à {service.name} - - -

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

-
-
-
- - {/* Decorative elements */} -
-
-
-
- ); -}; diff --git a/banquise-website/src/components/ui/ScrollToTopButton.tsx b/banquise-website/src/components/ui/ScrollToTopButton.tsx 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 ( - - ); -}; 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 !" - ''; -} -