diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index dfe0770..0000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml new file mode 100644 index 0000000..bd1371e --- /dev/null +++ b/.github/workflows/pr-build.yml @@ -0,0 +1,44 @@ +name: Build + +on: + pull_request: + branches: + - '**' + paths-ignore: + - '**.md' + - '**.adoc' + - 'docs/**' + - '.github/**' + - '.husky/**' + - 'LICENSE' + - 'COPYRIGHT' + - '.prettierignore' + - '.gitignore' + +concurrency: + group: build-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + build: + name: Next.js Build Check + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup pnpm + uses: pnpm/action-setup@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: lts/* + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm build diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml new file mode 100644 index 0000000..2fca289 --- /dev/null +++ b/.github/workflows/pr-lint.yml @@ -0,0 +1,34 @@ +name: Lint + +on: + pull_request: + branches: + - '**' + +concurrency: + group: lint-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + lint: + name: ESLint Check + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup pnpm + uses: pnpm/action-setup@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: lts/* + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run ESLint + run: pnpm lint diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..99ed15f --- /dev/null +++ b/.gitignore @@ -0,0 +1,64 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* +!.env.example + +# local +attached_assets +old-site +src/app/~test/locale +*.zip +.agents +.vercel +*.log + +# Editor / IDE +.idea/ +.replit +replit.nix +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# typescript +*.tsbuildinfo +next-env.d.ts + +# playwright +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/.hintrc b/.hintrc deleted file mode 100644 index 768aee6..0000000 --- a/.hintrc +++ /dev/null @@ -1,27 +0,0 @@ -{ - "extends": [ - "development" - ], - "hints": { - "no-inline-styles": "off", - "axe/forms": [ - "default", - { - "label": "off" - } - ], - "axe/name-role-value": [ - "default", - { - "button-name": "off" - } - ], - "axe/aria": [ - "default", - { - "aria-required-parent": "off" - } - ], - "button-type": "off" - } -} \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..5fcfc75 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +pnpm lint-staged \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..27b9377 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,34 @@ +# Dependencies +node_modules + +# Next.js +.next +out +build +dist + +# Generated files +next-env.d.ts +*.d.ts +*.tsbuildinfo + +# Config & lock files +package-lock.json +yarn.lock +pnpm-lock.yaml + +# Env files +.env +.env.* + +# Public assets +public + +# Cache / local +.cache +.turbo +.local +.agents +old-site/ + +tsconfig.json \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..7428885 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,12 @@ +{ + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "useTabs": false, + "trailingComma": "all", + "printWidth": 100, + "bracketSpacing": true, + "bracketSameLine": false, + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 5480842..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "kiroAgent.configureMCP": "Disabled" -} \ No newline at end of file diff --git a/404.html b/404.html deleted file mode 100644 index abf6249..0000000 --- a/404.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 404 - - - -

404 Not Found

-

Whoops! That page doesn't exist.

- -
-
-
- -
- - - \ No newline at end of file diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 0000000..bfee0d5 --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,10 @@ +OpenTune Web + +Copyright (C) 2024 Arturo Cervantes +Copyright (C) 2026 Rajnish Kumar + +This project is licensed under the GNU General Public License v3.0 +(GPL-3.0). + +For license terms, permissions, and conditions, refer to the LICENSE +file included with this repository. \ No newline at end of file diff --git a/LICENSE b/LICENSE index e62ec04..f288702 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -GNU GENERAL PUBLIC LICENSE + GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. diff --git a/PdP.html b/PdP.html deleted file mode 100644 index c1a9614..0000000 --- a/PdP.html +++ /dev/null @@ -1,198 +0,0 @@ - - - - - - - - - - - OpenTune - Política de Privacidad - - - - - - - - - - -
- -
- -
-
-
-
-
-

Política de Privacidad de - OpenTune

-
- - -
- -
-

- 1. Recopilación de Información -

-

En OpenTune, recopilamos información personal limitada necesaria para - proporcionar nuestros servicios de música. Esto puede incluir su nombre, dirección de correo - electrónico, preferencias de música y datos de uso.

-
- -
-

- 2. Uso de la Información -

-

La información recopilada se utiliza para mejorar la experiencia de - usuario y brindar contenido personalizado. Podemos utilizar esta información para recomendar - música, crear listas de reproducción personalizadas y comunicarnos con usted sobre - actualizaciones y novedades en la plataforma.

-
- -
-

- 3. Compartir Información -

-

No compartimos información personal con terceros sin su - consentimiento, excepto en situaciones legales donde esté permitido por la ley. Podemos - compartir información de forma anónima para realizar análisis y mejorar nuestros servicios.

-
- -
-

- 4. Seguridad -

-

Implementamos medidas de seguridad para proteger su información - personal contra accesos no autorizados, uso indebido o divulgación. Utilizamos cifrado de datos - y otras tecnologías para garantizar la seguridad de sus datos en nuestra plataforma.

-
- -
-

- 5. Cookies y Tecnologías Similares -

-

Utilizamos cookies y tecnologías similares para mejorar su experiencia - en OpenTune. Estas tecnologías nos permiten recordar sus preferencias, analizar el rendimiento - de la plataforma y personalizar el contenido que se le muestra.

- - -
- -
-

- 6. Cambios en la Política de Privacidad -

-

Nos reservamos el derecho de modificar nuestra Política de Privacidad - en cualquier momento. Cualquier cambio en la política se publicará en esta página. Le - recomendamos revisar periódicamente esta política para mantenerse informado sobre cómo - protegemos su información.

-
- -
-

- 7. Contacto -

-

Si tiene preguntas sobre nuestra Política de Privacidad o desea - ejercer sus derechos relacionados con sus datos personales, no dude en contactarnos.

-
- -
-
-

¿Tiene alguna pregunta?

-

Estamos aquí para - ayudar. Contáctenos si necesita más información.

- - - Contáctenos - -
-
-
-
-
- - \ No newline at end of file diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000..b8f92ad --- /dev/null +++ b/README.adoc @@ -0,0 +1,140 @@ += OpenTune Web +:toc: macro +:toc-title: Table of Contents +:icons: font +:experimental: +:source-highlighter: highlight.js + +image:https://img.shields.io/badge/License-GPL--3.0-blue.svg[License: GPL v3, link=https://www.gnu.org/licenses/gpl-3.0] +image:https://img.shields.io/badge/Next.js-16-black?logo=next.js[Next.js, link=https://nextjs.org/] +image:https://img.shields.io/badge/Tailwind_CSS-4.3-38B2AC?logo=tailwind-css[Tailwind CSS, link=https://tailwindcss.com/] +image:https://img.shields.io/badge/pnpm-11.5.3-orange?logo=pnpm[pnpm, link=https://pnpm.io/] +image:https://img.shields.io/badge/PRs-welcome-brightgreen.svg[PRs Welcome] + +Official website and landing page for *OpenTune*, an advanced YouTube Music client for Android featuring Material Design 3. + +🚀 **Explore the website at: https://opentune.netlify.app[opentune.netlify.app]** + +--- + +toc::[] + +== 📖 Overview + +OpenTune Web serves as the primary hub for the OpenTune project. It provides users with: +* Detailed feature showcases. +* Visual previews (screenshots) of the Android application. +* Direct download links for stable releases. +* Access to the community, support, and contribution guidelines. + +== 📱 OpenTune Android App Features + +OpenTune is built to provide a premium music experience without the limitations of the official app. + +* **Ad-Free:** No interruptions, just pure music. +* **Background Playback:** Listen while using other apps or with the screen off. +* **Material Design 3:** A modern, clean, and dynamic UI that follows the latest design trends. +* **Synced Lyrics:** Real-time lyrics for an immersive listening experience. +* **Offline Mode:** Download tracks and manage your local library efficiently. +* **Account Integration:** Seamlessly sync your YouTube Music library and preferences. +* **Advanced Audio:** Smart silence skipping, volume normalization, and playback speed/pitch control. +* **Android Auto:** Full integration for a safe music experience in your vehicle. + +== 🛠️ Web Tech Stack + +The website is engineered for speed, responsiveness, and global accessibility. + +[cols="1,3"] +|=== +| Component | Technology + +| **Framework** +| Next.js 16 (App Router) + +| **Styling** +| Tailwind CSS 4.3 + +| **Internationalization** +| `next-intl` + +| **Package Manager** +| pnpm + +| **Icons** +| Custom SVG System + Lucide React + +| **Deployment** +| Netlify +|=== + +== 🚀 Getting Started (Development) + +To run the project locally for development or testing: + +. **Clone the repository:** +[source,bash] +---- +git clone https://github.com/arturo254/opentune-web.git +cd opentune-web +---- + +. **Install dependencies:** +[source,bash] +---- +pnpm install +---- + +. **Start the development server:** +[source,bash] +---- +pnpm dev +---- + +. **Open the site:** +Navigate to `http://localhost:3000`. + +== 🌍 Localization + +OpenTune Web is available in several languages. Translations are managed via JSON files in `src/messages/`. + +* 🇺🇸 **English:** `en.json` (Source of truth) +* 🇪🇸 **Spanish:** `es.json` +* 🇮🇳 **Hindi:** `hi.json` +* 🇵🇹 **Portuguese:** `pt.json` + +[NOTE] +==== +To add a new language, create a copy of the English messages file: + +`cp -f src/messages/en.json src/messages/[lang].json` + +Then translate the messages in the newly created file. +==== + +== 🤝 Contributing + +We love contributions! Whether you're fixing a bug, suggesting a feature, or helping with translations. + +1. **Fork** the repository. +2. Create your **Feature Branch** (`git switch -c feature/AmazingFeature`). +3. **Commit** your changes (`git commit -m 'feat: Add some AmazingFeature'`). +4. **Push** to the branch (`git push origin feature/AmazingFeature`). +5. Open a **Pull Request**. + +== 🔗 Related Projects + +* **OpenTune Android App:** image:https://img.shields.io/github/v/release/Arturo254/OpenTune?logo=android&label=AndroidApp&color=181717&labelColor=41444a[Arturo254/OpenTune, link=https://github.com/Arturo254/OpenTune/] +* **Documentation:** image:https://img.shields.io/badge/Documentation-Read_Now-blue?logo=gitbook[Docs, link=https://opentune.gitbook.io/] + +== 📜 License + +This project is licensed under the **GPL-3.0 License**. See the `LICENSE` file for more information. + +== 💎 Credits + +* **Project Founder & Lead Designer:** https://github.com/Arturo254[Arturo Cervantes] +* **Web Lead Developer:** https://github.com/RajnishKMehta[Rajnish Kumar] +* **Contributors:** A huge thanks to all the community members helping build OpenTune! + +--- +_Built with passion for the Open Source Community._ diff --git a/README.md b/README.md deleted file mode 100644 index d321ec0..0000000 --- a/README.md +++ /dev/null @@ -1,131 +0,0 @@ -# OpenTune - -
- OpenTune Logo - - **Un cliente de YouTube Music con Material Design 3, para Android** - - [![Android](https://img.shields.io/badge/Platform-Android-brightgreen.svg)](https://android.com) - [![Material Design 3](https://img.shields.io/badge/Design-Material%20Design%203-blue.svg)](https://m3.material.io/) - [![License](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) - [![GitHub stars](https://img.shields.io/github/stars/Arturo254/OpenTune.svg)](https://github.com/Arturo254/OpenTune/stargazers) - - [📱 Descargar APK](https://github.com/Arturo254/OpenTune/releases) • [🌐 Sitio Web](https://opentune.arturodev.com) • [📋 Reportar Bug](https://opentune.arturodev.com/from.html) -
- -## ✨ Características Principales - -### 🎨 **Diseño Moderno** -- **Material Design 3**: Interfaz moderna con colores vivos y transiciones suaves -- **Tema adaptable**: Soporte para modo claro y oscuro -- **Interfaz intuitiva**: Navegación simplificada y personalizable - -### 🎵 **Funciones Musicales** -- **Reproducción de alta calidad**: Audio optimizado para diferentes dispositivos -- **Búsqueda avanzada**: Explora un amplio catálogo musical -- **Recomendaciones inteligentes**: Basadas en tus preferencias y hábitos -- **Listas de reproducción**: Crea y organiza tu música favorita -- **Descargas offline**: Escucha sin conexión a internet - -### 🔧 **Funcionalidades Avanzadas** -- **Control por voz**: Maneja la reproducción con comandos de voz -- **Soporte Chromecast**: Transmite a dispositivos externos -- **Conectividad Bluetooth**: Reproduce en dispositivos inalámbricos -- **Gestión de biblioteca**: Organización avanzada con filtros -- **Sincronización**: Integración completa con tu cuenta de YouTube Music - -### 🌍 **Soporte Internacional** -- **Multilingüe**: Español, English, Português -- **Localización cultural**: Traducciones precisas y relevantes -- **Actualizaciones continuas**: Mejoras regulares y nuevas funciones - -## 📱 Capturas de Pantalla - -
- OpenTune Preview -
- -## 🚀 Instalación - -### Android -1. Descarga el APK desde [Releases](https://github.com/Arturo254/OpenTune/releases) -2. Habilita la instalación de aplicaciones de fuentes desconocidas -3. Instala el archivo APK descargado -4. ¡Disfruta de OpenTune! - -### Windows -1. Descarga el archivo EXE desde [Releases](https://github.com/Arturo254/OpenTune/releases) -2. Ejecuta el instalador -3. Sigue las instrucciones de instalación - -## 🛠️ Tecnologías Utilizadas - -- **Android**: Kotlin -- **UI/UX**: Material Design 3 -- **Backend**: API de YouTube Music -- **Web**: HTML5, CSS3, JavaScript -- **Frameworks**: BeerCSS, Material Icons - -## 📋 Requisitos del Sistema - -### Android -- Android 6.0 (API nivel 23) o superior -- 50 MB de espacio libre -- Conexión a internet para streaming - -### Windows -- Windows 10 o superior -- 100 MB de espacio libre -- Conexión a internet - -## 🤝 Contribuir - -¡Las contribuciones son bienvenidas! Si quieres contribuir al proyecto: - -1. Haz fork del repositorio -2. Crea una rama para tu feature (`git checkout -b feature/nueva-caracteristica`) -3. Commit tus cambios (`git commit -am 'Añadir nueva característica'`) -4. Push a la rama (`git push origin feature/nueva-caracteristica`) -5. Abre un Pull Request - -### 🐛 Reportar Problemas -- [Reportar un bug](https://opentune.netlify.app/from.html) -- [Solicitar una característica](https://opentune.netlify.app/from) - -## 📞 Contacto y Soporte - -- **Desarrollador**: [Arthur Dev Studio](https://g.dev/Arturo254) -- **WhatsApp**: [+55 76 8479-25](https://wa.me/5576847925) -- **GitHub**: [@Arturo254](https://github.com/Arturo254) -- **Sitio Web**: [opentune.netlify.app](https://opentune.netlfy.app) - -## 📄 Licencia - -Este proyecto está licenciado bajo la Licencia MIT. Consulta el archivo [LICENSE](./LICENSE) para más detalles. - -## 🙏 Agradecimientos - -- Gracias a todos los [contribuidores](https://opentune.netlify.app/contribuidores/contribuidores) que han hecho posible este proyecto -- Material Design team por las guías de diseño -- Comunidad de YouTube Music por el feedback - -## 📊 Estadísticas del Proyecto - -
- -![GitHub release (latest by date)](https://img.shields.io/github/v/release/Arturo254/OpenTune) -![GitHub All Releases](https://img.shields.io/github/downloads/Arturo254/OpenTune/total) -![GitHub issues](https://img.shields.io/github/issues/Arturo254/OpenTune) -![GitHub pull requests](https://img.shields.io/github/issues-pr/Arturo254/OpenTune) - -
- ---- - -
- -**¿Te gusta OpenTune? ¡Dale una ⭐ al repositorio!** - -© 2024 [Arturo.inc™](https://github.com/Arturo254). Todos los derechos reservados. - -
diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 034e848..0000000 --- a/SECURITY.md +++ /dev/null @@ -1,21 +0,0 @@ -# Security Policy - -## Supported Versions - -Use this section to tell people about which versions of your project are -currently being supported with security updates. - -| Version | Supported | -| ------- | ------------------ | -| 5.1.x | :white_check_mark: | -| 5.0.x | :x: | -| 4.0.x | :white_check_mark: | -| < 4.0 | :x: | - -## Reporting a Vulnerability - -Use this section to tell people how to report a vulnerability. - -Tell them where to go, how often they can expect to get an update on a -reported vulnerability, what to expect if the vulnerability is accepted or -declined, etc. diff --git a/beta.html b/beta.html deleted file mode 100644 index 8bd5188..0000000 --- a/beta.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - Beta Program - - -
- -
-
- - -
- -
Download the private beta version
-
-

You can sign up for the waiting list to be accepted and thus be able to try out new features.

- - waiting list - - -
- - - -
- - \ No newline at end of file diff --git a/contribuidores/contribuidores -en.html b/contribuidores/contribuidores -en.html deleted file mode 100644 index 237b80f..0000000 --- a/contribuidores/contribuidores -en.html +++ /dev/null @@ -1,656 +0,0 @@ - - - - - - - Contributors — OpenTune - - - - - - - - - - - - - - - - - - - - - -
-
- - Contributors -
-
- - -
-
- - - -
Language
-
- - Español - - - English - - - Português (BR) - -
- -
- - -
- - - -
- - -
- Arturo Cervantes - Arturo Cervantes - Lead Developer - - engineering - Lead Dev - - -
- - -
- Fabiano Júnior - Fabiano Júnior - Portuguese (BR) Translator - - translate - Translation BR - - -
- - -
- Imgbot - Imgbot - Image Optimization - - image - Bot - - -
- -
- - -
- fork_right -

Want to contribute?

-

Fork the repository and submit a pull request. All contributions are welcome!

- - add - Fork Repository - -
- -
- - - - - - \ No newline at end of file diff --git a/contribuidores/contribuidores-Pr_Br.html b/contribuidores/contribuidores-Pr_Br.html deleted file mode 100644 index d5726bc..0000000 --- a/contribuidores/contribuidores-Pr_Br.html +++ /dev/null @@ -1,676 +0,0 @@ - - - - - - - Colaboradores — OpenTune - - - - - - - - - - - - - - - - - - - - - -
- -
- - -
-
- - - -
Idioma
-
- - Español - - - English - - - Português (BR) - -
- -
- - -
- - - -
- - -
- Arturo Cervantes - Arturo Cervantes - Desenvolvedor Principal - - engineering - Dev Principal - - -
- - -
- Fabiano Júnior - Fabiano Júnior - Tradutor para o Português (BR) - - translate - Tradução BR - - -
- - -
- Imgbot - Imgbot - Otimização de Imagens - - image - Bot - - -
- - -
- รiłѵα'.ぁ™ - รiłѵα'.ぁ™ - Tradução e correções para o Português (BR) - - edit - Correções BR - - -
- -
- - -
- fork_right -

Quer contribuir?

-

Faça um fork do repositório e envie seu pull request. Toda ajuda é bem-vinda!

- - add - Fazer Fork - -
- -
- - - - - - \ No newline at end of file diff --git a/contribuidores/contribuidores.html b/contribuidores/contribuidores.html deleted file mode 100644 index ed59ba5..0000000 --- a/contribuidores/contribuidores.html +++ /dev/null @@ -1,365 +0,0 @@ - - - - - - - - - - - - - - - - - -
-
OpenTune
-
- - -
-
- -
- -
-
- volunteer_activism - Excelencia de Código Abierto -
-

Comunidad y Colaboradores

-

OpenTune es construido por la - comunidad, - para la comunidad. Cada commit, reporte de error y traducción nos acerca a la mejor experiencia de música de - código - abierto.

-
- - -
-
- star - --- - Estrellas -
-
- fork_right - --- - Bifurcaciones -
-
- error_outline - --- - Incidencias Abiertas -
-
- history - --- - Total de Commits -
-
- - -
-
-

Principales Colaboradores

- - Ver Todos arrow_forward - -
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - -
- -
-
-
-

Cómo Ayudar

-

Elige tu camino y ayúdanos a hacer OpenTune aún - mejor.

-
-
-
-
- terminal - Programación -
-

Implementa nuevas funciones o corrige errores - en nuestra base de código en Kotlin.

- Explorar - Incidencias -
-
-
- palette - Diseño UI/UX -
-

Mejora la implementación de Material 3 y el - acabado visual.

- -
-
-
- translate - Traducción -
-

Ayúdanos a localizar OpenTune para los amantes - de la música en todo el mundo.

- -
-
-
- bug_report - Reportar Errores -
-

¿Encontraste un fallo? Los reportes detallados - nos ayudan a mantener la estabilidad.

- Abrir - Incidencia -
-
-
- - -
-

Última Actividad

-
-
-
-
-
-
- - Ver Actividad en GitHub - -
-
-
- - - - - - - \ No newline at end of file diff --git a/css/styles.css b/css/styles.css deleted file mode 100644 index b6b2826..0000000 --- a/css/styles.css +++ /dev/null @@ -1,750 +0,0 @@ -/* ══════════════════════════════════════════════ - OpenTune Web — Custom Styles - Complementa Tailwind CSS con estilos glassmórficos, - dialogs, animaciones y componentes personalizados. - ══════════════════════════════════════════════ */ - -/* ─── Base ─── */ -html { - scroll-behavior: smooth; -} - -*, ::before, ::after { - box-sizing: border-box; -} - -a { - text-decoration: none; -} - -/* ─── Material Symbols ─── */ -.material-symbols-outlined { - font-family: 'Material Symbols Outlined'; - font-weight: normal; - font-style: normal; - font-size: 24px; - line-height: 1; - letter-spacing: normal; - text-transform: none; - display: inline-block; - white-space: nowrap; - word-wrap: normal; - direction: ltr; - -webkit-font-smoothing: antialiased; - font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; - vertical-align: middle; -} - -/* ─── Glass Card ─── */ -.glass-card { - background: rgba(20, 19, 23, 0.45); - backdrop-filter: blur(24px); - -webkit-backdrop-filter: blur(24px); - border: 1px solid rgba(255, 255, 255, 0.06); -} - -/* ─── Ambient Glow ─── */ -.ambient-glow { - box-shadow: 0 0 40px 0 rgba(208, 188, 255, 0.15); -} - -/* ─── Feature Icon Wrapper ─── */ -.feature-icon-wrap { - width: 48px; - height: 48px; - border-radius: 9999px; - display: flex; - align-items: center; - justify-content: center; - margin-bottom: 16px; - flex-shrink: 0; -} - -/* ─── Version Chips ─── */ -.version-chip { - display: inline-flex; - align-items: center; - padding: 4px 12px; - border-radius: 9999px; - background-color: rgba(43, 41, 45, 0.8); - color: #cac4d0; - font-size: 11px; - font-weight: 500; - font-family: 'Be Vietnam Pro', sans-serif; - line-height: 16px; -} - -.version-chip--stable { - background-color: rgba(239, 184, 200, 0.18); - color: #ffd9e3; -} - -.version-chip--beta { - background-color: rgba(74, 67, 89, 0.6); - color: #ccc2dc; -} - -.version-chip--alpha { - background-color: rgba(208, 188, 255, 0.15); - color: #e9ddff; -} - -.version-chip--latest { - background-color: rgba(208, 188, 255, 0.18); - color: #d0bcff; -} - -/* ─── Footer Chips ─── */ -.footer-chip { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 8px 16px; - border-radius: 9999px; - border: 1px solid rgba(73, 69, 79, 0.5); - color: #948f9a; - font-size: 13px; - font-family: 'Be Vietnam Pro', sans-serif; - font-weight: 500; - transition: all 0.2s cubic-bezier(0.2, 0, 0, 1); -} - -.footer-chip:hover { - border-color: rgba(208, 188, 255, 0.4); - color: #d0bcff; - background: rgba(208, 188, 255, 0.07); - transform: translateY(-1px); -} - -/* ─── Developer Chip Animation ─── */ -.developer-chip { - animation: shine 3.5s ease-in-out infinite; -} - -@keyframes shine { - 0%, 100% { opacity: 1; transform: scale(1); } - 50% { opacity: 0.8; transform: scale(1.04); } -} - -/* ══════════════════════════════════════════════ - GLASS DIALOGS - ══════════════════════════════════════════════ */ - -.glass-dialog { - position: fixed; - inset: 0; - margin: auto; - width: min(90vw, 480px); - max-height: 85vh; - border: none; - border-radius: 2rem; - background: rgba(18, 17, 22, 0.88); - backdrop-filter: blur(32px); - -webkit-backdrop-filter: blur(32px); - border: 1px solid rgba(255, 255, 255, 0.08); - color: #e5e1e7; - overflow: hidden; - padding: 0; - box-shadow: - 0 30px 70px rgba(0, 0, 0, 0.55), - 0 0 0 1px rgba(208, 188, 255, 0.06), - inset 0 1px 0 rgba(255, 255, 255, 0.05); -} - -.glass-dialog--large { - width: min(90vw, 600px); -} - -.glass-dialog::backdrop { - background: rgba(0, 0, 0, 0.72); - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); -} - -/* Dialog layout */ -.dialog-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 24px 24px 0; - gap: 12px; -} - -.dialog-content { - padding: 20px 24px; -} - -.dialog-content--scroll { - overflow-y: auto; - max-height: 58vh; -} - -.dialog-content--scroll::-webkit-scrollbar { - width: 4px; -} -.dialog-content--scroll::-webkit-scrollbar-track { - background: transparent; -} -.dialog-content--scroll::-webkit-scrollbar-thumb { - background: rgba(208, 188, 255, 0.25); - border-radius: 2px; -} - -.dialog-actions { - display: flex; - justify-content: flex-end; - gap: 8px; - padding: 0 24px 24px; -} - -/* Dialog buttons */ -.dialog-icon-btn { - width: 36px; - height: 36px; - border: none; - border-radius: 9999px; - background: transparent; - color: #cac4d0; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: background 0.2s; - flex-shrink: 0; -} - -.dialog-icon-btn:hover { - background: rgba(255, 255, 255, 0.08); -} - -.dialog-text-btn { - background: transparent; - border: none; - color: #d0bcff; - font-family: 'Be Vietnam Pro', sans-serif; - font-size: 14px; - font-weight: 500; - padding: 10px 20px; - border-radius: 9999px; - cursor: pointer; - transition: background 0.2s; -} - -.dialog-text-btn:hover { - background: rgba(208, 188, 255, 0.1); -} - -.dialog-filled-btn { - background: #d0bcff; - border: none; - color: #37265e; - font-family: 'Be Vietnam Pro', sans-serif; - font-size: 14px; - font-weight: 500; - padding: 10px 24px; - border-radius: 9999px; - cursor: pointer; - transition: all 0.2s; -} - -.dialog-filled-btn:hover { - filter: brightness(1.1); -} - -.dialog-filled-btn:active { - transform: scale(0.96); -} - -/* Dialog list items (language) */ -.dialog-list-item { - display: flex; - align-items: center; - gap: 12px; - padding: 12px 16px; - border-radius: 1rem; - color: #e5e1e7; - font-family: 'Be Vietnam Pro', sans-serif; - transition: background 0.2s; - cursor: pointer; -} - -.dialog-list-item:hover { - background: rgba(255, 255, 255, 0.06); -} - -.flag-icon { - width: 24px; - height: 18px; - border-radius: 3px; - object-fit: cover; - flex-shrink: 0; -} - -/* ══════════════════════════════════════════════ - LOADING INDICATOR - ══════════════════════════════════════════════ */ - -.loading-indicator { - display: flex; - justify-content: center; - align-items: center; - padding: 56px 40px; -} - -.circular-progress { - width: 36px; - height: 36px; - border: 3px solid rgba(208, 188, 255, 0.18); - border-top: 3px solid #d0bcff; - border-radius: 50%; - animation: spin 0.85s linear infinite; -} - -@keyframes spin { - to { transform: rotate(360deg); } -} - -/* ══════════════════════════════════════════════ - MARKDOWN BODY (changelog) - ══════════════════════════════════════════════ */ - -.markdown-body h1, -.markdown-body h2, -.markdown-body h3 { - color: #e5e1e7; - font-family: 'Epilogue', sans-serif; - margin: 20px 0 10px; -} - -.markdown-body h1 { font-size: 1.4rem; font-weight: 700; } -.markdown-body h2 { font-size: 1.15rem; font-weight: 600; } -.markdown-body h3 { font-size: 1rem; font-weight: 600; } - -.markdown-body p { - color: #cac4d0; - line-height: 1.75; - margin: 8px 0; -} - -.markdown-body ul, -.markdown-body ol { - color: #cac4d0; - padding-left: 22px; - margin: 8px 0; - line-height: 1.75; -} - -.markdown-body li { - margin: 4px 0; -} - -.markdown-body code { - background: rgba(208, 188, 255, 0.12); - color: #d0bcff; - padding: 2px 8px; - border-radius: 6px; - font-size: 0.82em; - font-family: ui-monospace, 'Courier New', monospace; -} - -.markdown-body pre { - background: rgba(14, 14, 17, 0.7); - border: 1px solid rgba(73, 69, 79, 0.4); - border-radius: 12px; - padding: 16px; - overflow-x: auto; - margin: 12px 0; -} - -.markdown-body pre code { - background: transparent; - padding: 0; - color: #e5e1e7; -} - -.markdown-body a { - color: #d0bcff; - text-decoration: underline; - text-underline-offset: 3px; -} - -.markdown-body a:hover { - color: #e9ddff; -} - -.markdown-body hr { - border: none; - border-top: 1px solid rgba(73, 69, 79, 0.5); - margin: 20px 0; -} - -/* Changelog meta header */ -.changelog-meta { - display: flex; - flex-direction: column; - gap: 8px; - margin-bottom: 20px; - padding-bottom: 16px; - border-bottom: 1px solid rgba(73, 69, 79, 0.4); -} - -.changelog-date { - font-size: 13px; - color: #948f9a; - font-family: 'Be Vietnam Pro', sans-serif; -} - -/* ══════════════════════════════════════════════ - VERSION LIST (versions dialog) - ══════════════════════════════════════════════ */ - -.version-list-item { - display: flex; - align-items: center; - justify-content: space-between; - padding: 14px 0; - gap: 12px; - border-bottom: 1px solid rgba(73, 69, 79, 0.3); -} - -.version-list-item:last-child { - border-bottom: none; -} - -.version-list-info { - display: flex; - flex-direction: column; - gap: 6px; - flex: 1; - min-width: 0; -} - -.version-meta-row { - display: flex; - align-items: center; - gap: 6px; - flex-wrap: wrap; -} - -.version-tag { - font-size: 15px; - font-weight: 500; - color: #e5e1e7; - font-family: 'Be Vietnam Pro', sans-serif; -} - -.version-date { - font-size: 12px; - color: #948f9a; - font-family: 'Be Vietnam Pro', sans-serif; -} - -.version-dl-btn { - display: inline-flex; - align-items: center; - gap: 6px; - background: rgba(43, 41, 45, 0.8); - color: #e5e1e7; - border: 1px solid rgba(73, 69, 79, 0.4); - padding: 8px 16px; - border-radius: 9999px; - font-size: 13px; - font-weight: 500; - font-family: 'Be Vietnam Pro', sans-serif; - text-decoration: none; - transition: all 0.2s; - flex-shrink: 0; - white-space: nowrap; -} - -.version-dl-btn:hover { - background: rgba(53, 52, 56, 0.9); - border-color: rgba(208, 188, 255, 0.3); - color: #d0bcff; -} - -/* ══════════════════════════════════════════════ - DISABLED CARD (Windows) - ══════════════════════════════════════════════ */ - -.disabled-card { - position: relative; - overflow: hidden; - cursor: not-allowed; - user-select: none; - -webkit-user-select: none; -} - -/* Diagonal stripe overlay */ -.disabled-card::before { - content: ''; - position: absolute; - inset: 0; - background: repeating-linear-gradient( - -45deg, - transparent, - transparent 14px, - rgba(255, 255, 255, 0.018) 14px, - rgba(255, 255, 255, 0.018) 28px - ); - pointer-events: none; - z-index: 0; -} - -.disabled-card__inner { - position: relative; - z-index: 1; - opacity: 0.5; - pointer-events: none; -} - -/* ══════════════════════════════════════════════ - SCROLLBAR (global) - ══════════════════════════════════════════════ */ - -::-webkit-scrollbar { - width: 6px; -} - -::-webkit-scrollbar-track { - background: transparent; -} - -::-webkit-scrollbar-thumb { - background: rgba(208, 188, 255, 0.2); - border-radius: 3px; -} - -::-webkit-scrollbar-thumb:hover { - background: rgba(208, 188, 255, 0.38); -} - -/* ══════════════════════════════════════════════ - FOCUS VISIBLE - ══════════════════════════════════════════════ */ - -:focus-visible { - outline: 2px solid #d0bcff; - outline-offset: 2px; - border-radius: 4px; -} - -/* ══════════════════════════════════════════════ - LIGHT MODE OVERRIDES - (activa con root.classList.add('light-mode')) - ══════════════════════════════════════════════ */ - -:root.light-mode { - --lm-bg: #FEF7FF; - --lm-on-bg: #1D1B20; - --lm-surface: #FEF7FF; - --lm-on-surface: #1D1B20; - --lm-sc-low: #F7F2FA; - --lm-sc: #F3EDF7; - --lm-sc-high: #ECE6F0; - --lm-sc-highest: #E6E0E9; - --lm-primary: #6750A4; - --lm-on-primary: #FFFFFF; - --lm-pc: #EADDFF; - --lm-on-pc: #21005D; - --lm-sec-c: #E8DEF8; - --lm-on-sec-c: #1D192B; - --lm-on-sv: #49454F; - --lm-ov: #CAC4D0; -} - -:root.light-mode body { - background-color: var(--lm-bg); - color: var(--lm-on-bg); -} - -:root.light-mode .bg-background { background-color: var(--lm-bg) !important; } -:root.light-mode .bg-surface { background-color: var(--lm-surface) !important; } -:root.light-mode .bg-surface-container-lowest { background-color: var(--lm-sc-low) !important; } -:root.light-mode .bg-surface-container-high { background-color: var(--lm-sc-high) !important; } -:root.light-mode .bg-surface-container-highest{ background-color: var(--lm-sc-highest) !important; } -:root.light-mode .bg-primary-container { background-color: var(--lm-pc) !important; } -:root.light-mode .bg-secondary-container { background-color: var(--lm-sec-c) !important; } -:root.light-mode .bg-primary { background-color: var(--lm-primary) !important; } - -:root.light-mode .text-on-surface { color: var(--lm-on-surface) !important; } -:root.light-mode .text-on-surface-variant { color: var(--lm-on-sv) !important; } -:root.light-mode .text-on-background { color: var(--lm-on-bg) !important; } -:root.light-mode .text-on-primary { color: var(--lm-on-primary) !important; } -:root.light-mode .text-on-primary-container { color: var(--lm-on-pc) !important; } -:root.light-mode .text-on-secondary-container { color: var(--lm-on-sec-c) !important; } -:root.light-mode .text-primary { color: var(--lm-primary) !important; } -:root.light-mode .text-violet-300 { color: var(--lm-primary) !important; } -:root.light-mode .text-slate-400 { color: var(--lm-on-sv) !important; } -:root.light-mode .text-slate-500 { color: #79747E !important; } -:root.light-mode .text-slate-100 { color: var(--lm-on-surface) !important; } -:root.light-mode .text-surface { color: var(--lm-surface) !important; } - -:root.light-mode .border-outline-variant { border-color: var(--lm-ov) !important; } -:root.light-mode .border-white\/10 { border-color: rgba(0, 0, 0, 0.08) !important; } -:root.light-mode .border-white\/5 { border-color: rgba(0, 0, 0, 0.05) !important; } - -:root.light-mode .bg-slate-950\/65 { background-color: rgba(254, 247, 255, 0.82) !important; } -:root.light-mode .bg-slate-950 { background-color: #F7F2FA !important; } - -:root.light-mode .glass-card { - background: rgba(255, 255, 255, 0.65); - border-color: rgba(0, 0, 0, 0.06); -} - -:root.light-mode .glass-dialog { - background: rgba(240, 236, 248, 0.92); - border-color: rgba(0, 0, 0, 0.08); - color: #1D1B20; -} - -:root.light-mode .glass-dialog::backdrop { - background: rgba(0, 0, 0, 0.42); -} - -:root.light-mode .dialog-text-btn { color: var(--lm-primary); } -:root.light-mode .dialog-text-btn:hover { background: rgba(103, 80, 164, 0.1); } -:root.light-mode .dialog-icon-btn { color: var(--lm-on-sv); } -:root.light-mode .dialog-icon-btn:hover { background: rgba(0,0,0,0.06); } -:root.light-mode .dialog-list-item { color: var(--lm-on-surface); } -:root.light-mode .dialog-list-item:hover { background: rgba(0,0,0,0.05); } -:root.light-mode .dialog-filled-btn { background: var(--lm-primary); color: var(--lm-on-primary); } - -:root.light-mode .footer-chip { - border-color: rgba(0, 0, 0, 0.12); - color: #49454F; -} -:root.light-mode .footer-chip:hover { - border-color: var(--lm-primary); - color: var(--lm-primary); - background: rgba(103, 80, 164, 0.06); -} - -:root.light-mode .circular-progress { - border-color: rgba(103, 80, 164, 0.18); - border-top-color: var(--lm-primary); -} - -:root.light-mode .version-chip { - background-color: rgba(231, 224, 236, 0.9); - color: #49454F; -} - -:root.light-mode .version-dl-btn { - background: rgba(231, 224, 236, 0.8); - border-color: rgba(0, 0, 0, 0.1); - color: #1D1B20; -} -:root.light-mode .version-dl-btn:hover { - border-color: var(--lm-primary); - color: var(--lm-primary); -} - -:root.light-mode .markdown-body h1, -:root.light-mode .markdown-body h2, -:root.light-mode .markdown-body h3 { color: #1D1B20; } -:root.light-mode .markdown-body p, -:root.light-mode .markdown-body li { color: #49454F; } -:root.light-mode .markdown-body code { - background: rgba(103, 80, 164, 0.1); - color: var(--lm-primary); -} -:root.light-mode .markdown-body a { color: var(--lm-primary); } - -:root.light-mode .ambient-glow { - box-shadow: 0 0 40px 0 rgba(103, 80, 164, 0.18); -} - -:root.light-mode .from-surface { - --tw-gradient-from: #FEF7FF var(--tw-gradient-from-position); -} - -/* ══════════════════════════════════════════════ - ACCESSIBILITY & PERFORMANCE - ══════════════════════════════════════════════ */ - -@media (prefers-reduced-motion: reduce) { - *, ::before, ::after { - animation-duration: 0.01ms !important; - transition-duration: 0.01ms !important; - } -} - -@media (prefers-contrast: high) { - .glass-card { - border-width: 2px; - border-color: rgba(255, 255, 255, 0.25); - } - .glass-dialog { - border-width: 2px; - } -} - -/* ══════════════════════════════════════════════ - RESPONSIVE FIXES - ══════════════════════════════════════════════ */ - -@media (max-width: 640px) { - .glass-dialog { - width: 92vw; - border-radius: 1.5rem; - max-height: 88vh; - } - - .dialog-header { - padding: 20px 18px 0; - } - - .dialog-content { - padding: 16px 18px; - } - - .dialog-actions { - padding: 0 18px 20px; - } -} - -@media (max-width: 480px) { - .version-list-item { - flex-direction: column; - align-items: flex-start; - } - - .version-dl-btn { - width: 100%; - justify-content: center; - } -} - -/* ─── Screenshots Accordion ─── */ -#screenshots-content { - max-height: 2000px; - opacity: 1; - overflow: hidden; - transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), - opacity 0.3s ease, - margin 0.3s ease; -} - -#screenshots-content.collapsed { - max-height: 0 !important; - opacity: 0; - margin: 0; - padding: 0; -} - -#screenshots-icon { - transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); -} - -#screenshots-icon.rotated { - transform: rotate(180deg); -} - -#screenshots-header:hover #screenshots-toggle { - background: rgba(255, 255, 255, 0.08); -} - - @keyframes spin { - to { transform: rotate(360deg); } - } \ No newline at end of file diff --git a/en.html b/en.html deleted file mode 100644 index 42305fa..0000000 --- a/en.html +++ /dev/null @@ -1,741 +0,0 @@ - - - - - - - - - - - - - - OpenTune - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Select Language

- -
- - -
- - - -
-
-
- warning -
-

Redirect Notice

-
-
-
-

You will be redirected outside of OpenTune Web to an - external demo provided by Appetize.io.

-
-
- - -
-
- - - - - - - - -
- - -
- -
-
-
-
- -
- -
- -
- code - Dev By Arthur Dev Studio -
- -

OpenTune

-

- A YouTube Music client with Material Design 3, for Android. -

- -
- - download - Download APK - - -
-
- - -
-
- OpenTune App Preview -
-
-
-
-
-
- - -
-
-
-

Features

-

- Discover all the features that make OpenTune the best client for your music. -

-
- -
- -
-
- music_note -
-

YouTube Music Client with Material Design 3 -

-

Provides a modern and elegant - YouTube Music experience on Android, with an intuitive and optimized interface.

-
- -
-
- palette -
-

Modern and Attractive Design

-

Based on Material Design 3, with - vivid colors, modern typography, and smooth transitions.

-
- -
-
- settings -
-

Intuitive and Customizable Interface

-

Simplified interface for quick - access to all features, with customization options.

-
- -
-
- search -
-

Explore and Discover Music

-

Access to a vast music catalog - with advanced search and smart recommendations.

-
- -
-
- volume_up -
-

High-Quality Playback

-

High-quality music, optimized - for different devices and network conditions.

-
- -
-
- playlist_add -
-

Playlists and Downloads

-

Create and organize playlists, - and download songs to listen offline.

-
- -
-
- sync -
-

YouTube Music Integration

-

Sync your YouTube Music account - to access your libraries and receive notifications.

-
- -
-
- build -
-

Advanced Features

-

Voice and gesture playback - control, with Chromecast and Bluetooth support.

-
- -
-
- folder -
-

Efficient Library Management

-

Organize your music with - advanced filtering and categorization tools.

-
- -
-
- translate -
-

Multilingual Support

-

Available in multiple languages - with accurate translations and culturally relevant localization.

-
- -
-
- update -
-

Continuous Updates

-

Regular updates with new - features, security improvements, and optimization.

-
- -
-
- headphones -
-

Optimized User Experience

-

Intuitive navigation and agile - performance with a user-friendly interface that enhances the experience.

-
-
-
-
- - -
-
-
- COMMUNITY - DRIVEN -

Open Source at its Heart

-

OpenTune is built by music lovers for music - lovers. Contribute, customize, and help us build the best open-source player for Android.

-
- - star - Star on GitHub - -
- GPL-3.0 -
-
-
- -
-
-
- -
-
-

Arturo254

-

Lead Developer

-
-
-
-
- verified -
-
-

Latest stable version

-

Loading...

-
-
-
-
-
-
-
- - -
-
- -
-
-
-

The Interface

-

A glimpse at the OpenTune experience.

-
- -
-
- - - -
-
- - -
-
-
-
- support_agent -
-

Need Help?

-

- Submit a request or report an issue directly to the development team. -

- - send - Request Help - -
-
-
- - -
-
-
-

Downloads

-

- Download the latest version of OpenTune for your platform. -

-
- -
- - -
-
-
- android -
-
-

Android

-

Download the latest stable version.

-
-
- -
- Stable Version - Loading... -
- -
- - -
- -
- - download - Download APK - -

Requires Android 8.0+

-
-
- - - - -
-
-
-
- laptop_windows -
-
-

Windows

-

Development is currently closed. -

-
-
- -
- Closed - Not Available -
- -
- - list_alt - View Changes - - - history - Previous Versions - -
- -
- -
-
-
- -
-
-
- -
- - - - - - - - -
-

Changelog

- -
-
-
-
-
-
-
- - - -
-

Previous Versions

- -
-
-
-
-
-
-
- - - - - diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..2b23ca9 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,44 @@ +import { defineConfig, globalIgnores } from 'eslint/config'; +import nextVitals from 'eslint-config-next/core-web-vitals'; +import nextTs from 'eslint-config-next/typescript'; + +export default defineConfig([ + ...nextVitals, + ...nextTs, + + { + rules: { + // Allow console.warn() and console.error() + 'no-console': [ + 'warn', + { + allow: ['warn', 'error'], + }, + ], + + // Prevent == and != + eqeqeq: ['error', 'always'], + + // Always require braces + curly: ['error', 'all'], + + // Catch unused variables + '@typescript-eslint/no-unused-vars': [ + 'error', + { + argsIgnorePattern: '^\\$', + varsIgnorePattern: '^\\$', + caughtErrorsIgnorePattern: '^\\$', + }, + ], + + // Discourage unnecessary state updates inside useEffect + 'react-hooks/set-state-in-effect': 'warn', + + // Prefer const when variable isn't reassigned + 'prefer-const': 'error', + }, + }, + + globalIgnores(['.next/**', 'out/**', 'build/**', 'next-env.d.ts', '.local/**']), +]); diff --git a/from.html b/from.html deleted file mode 100644 index bf9ada2..0000000 --- a/from.html +++ /dev/null @@ -1,308 +0,0 @@ - - - - - - - - - - - - - - - - - - -
-
- -
OpenTune
- - - - - -
-
-
-
- -
-

Enviar Comentario

-

Envía tu problema o describe tu solicitud

-
- -
- -
-
- -
- -
- person - -
-
- -
- -
- - - - - - -
-
- -
- - -
- -
- -
- alternate_email - -
-
- -
- -
-
-
- -
-
- verified_user -
-

Privacidad Asegurada

-

Tus datos están protegidos y solo se usarán para - contactarte sobre tu reporte.

-
-
-
- schedule -
-

Tiempo de Respuesta

-

Normalmente respondemos en mas de 24 horas - debido a la alta demanda de solicitudes.

-
-
-
-
- - - - - - - \ No newline at end of file diff --git a/index.html b/index.html deleted file mode 100644 index a1571dc..0000000 --- a/index.html +++ /dev/null @@ -1,744 +0,0 @@ - - - - - - - - - - - - - - OpenTune - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Seleccionar idioma

- -
- - -
- - - -
-
-
- warning -
-

Aviso de Redirección

-
-
-
-

Serás redirigido fuera de OpenTune Web a una demostración - externa proporcionada por Appetize.io.

-
-
- - -
-
- - - - - - - - -
- - -
- -
-
-
-
- -
- -
- -
- code - Dev By Arthur Dev Studio -
- -

OpenTune

-

- Un cliente de YouTube Music con Material Design 3, para Android. -

- -
- - download - Descargar APK - - -
-
- - -
-
- OpenTune App Preview -
-
-
-
-
-
- - -
-
-
-

Características

-

- Descubre todas las funciones que hacen de OpenTune el mejor cliente para tu música. -

-
- -
- -
-
- music_note -
-

Cliente de YouTube Music con Material Design 3 -

-

Ofrece una experiencia moderna y - elegante de YouTube Music en Android, con una interfaz intuitiva y optimizada.

-
- -
-
- palette -
-

Diseño Moderno y Atractivo

-

Basado en Material Design 3, con - colores vivos, tipografía moderna y transiciones suaves.

-
- -
-
- settings -
-

Interfaz Intuitiva y Personalizable

-

Interfaz simplificada para un acceso - rápido a todas las funciones, con opciones de personalización.

-
- -
-
- search -
-

Explora y Descubre Música

-

Acceso a un amplio catálogo musical - con búsqueda avanzada y recomendaciones inteligentes.

-
- -
-
- volume_up -
-

Reproducción de Alta Calidad

-

Música de alta calidad, optimizada - para diferentes dispositivos y condiciones de red.

-
- -
-
- playlist_add -
-

Listas de Reproducción y Descargas

-

Crea y organiza listas de - reproducción, y descarga canciones para escuchar sin conexión.

-
- -
-
- sync -
-

Integración con YouTube Music

-

Sincroniza tu cuenta de YouTube Music - para acceder a tus bibliotecas y recibir notificaciones.

-
- -
-
- build -
-

Funcionalidades Avanzadas

-

Control de reproducción con voz, - gestos y soporte para Chromecast y Bluetooth.

-
- -
-
- folder -
-

Gestión Eficiente de la Biblioteca

-

Organiza tu música con herramientas - avanzadas de filtrado y categorización.

-
- -
-
- translate -
-

Soporte Multilingüe

-

Disponible en varios idiomas con - traducciones precisas y localización culturalmente relevante.

-
- -
-
- update -
-

Actualizaciones Continuas

-

Actualizaciones regulares con nuevas - funciones, mejoras de seguridad y optimización.

-
- -
-
- headphones -
-

Experiencia de Usuario Optimizada

-

Navegación intuitiva y rendimiento - ágil con una interfaz amigable que mejora la experiencia.

-
-
-
-
- - -
-
-
- COMMUNITY - DRIVEN -

Open Source at its Heart

-

OpenTune es construido por amantes de la música - para amantes de la música. Contribuye, personaliza y ayúdanos a construir el mejor reproductor - de código abierto para Android.

-
- - star - Star on GitHub - -
- GPL-3.0 -
-
-
- -
-
-
- -
-
-

Arturo254

-

Lead Developer

-
-
-
-
- verified -
-
-

Última versión estable

-

Cargando...

-
-
-
-
-
-
-
- - -
-
- -
-
-
-

La Interfaz

-

Un vistazo a la experiencia de OpenTune.

-
- -
-
- - - -
-
- - -
-
-
-
- support_agent -
-

¿Necesitas ayuda?

-

- Envía una solicitud o reporta un problema directamente al equipo de desarrollo. -

- - send - Solicitar ayuda - -
-
-
- - -
-
-
-

Descargas

-

- Descarga la versión más reciente de OpenTune para tu plataforma. -

-
- -
- - -
-
-
- android -
-
-

Android

-

Descarga la última versión estable.

-
-
- -
- Versión Estable - Cargando... -
- -
- - -
- -
- - download - Descargar APK - -

Requiere Android 8.0+

-
-
- - - - -
-
-
-
- laptop_windows -
-
-

Windows

-

El desarrollo está cerrado actualmente. -

-
-
- -
- Cerrado - No disponible -
- -
- - list_alt - Ver cambios - - - history - Versiones anteriores - -
- -
- -
-
-
- -
-
-
- -
- - - - - - - - -
-

Registro de cambios

- -
-
-
-
-
-
-
- - - -
-

Versiones anteriores

- -
-
-
-
-
-
-
- - - - - - - \ No newline at end of file diff --git a/knip.config.ts b/knip.config.ts new file mode 100644 index 0000000..024f9b3 --- /dev/null +++ b/knip.config.ts @@ -0,0 +1,17 @@ +import type { KnipConfig } from 'knip'; + +const config: KnipConfig = { + project: ['src/**/*.{ts,tsx}', 'src/**/*.{test,spec}.{ts,tsx}'], + + entry: ['src/app/**/*.{ts,tsx}', 'src/*.{ts,tsx}'], + + ignore: ['src/app/~test/locale/**/*.{ts,tsx}', 'src/app/~test/locale/*.{ts,tsx}'], + + ignoreDependencies: ['tailwindcss'], + + // Uncomment for production mode analysis (excludes tests/dev) + // productionEntry: ['src/app/**/*.{ts,tsx}!'], + // productionProject: ['src/**/*.{ts,tsx}!', '!src/**/*.{test,spec,stories}.{ts,tsx}'], +}; + +export default config; diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000..46be800 --- /dev/null +++ b/next.config.ts @@ -0,0 +1,16 @@ +import type { NextConfig } from 'next'; +import createNextIntlPlugin from 'next-intl/plugin'; + +const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts'); + +const nextConfig: NextConfig = { + images: { + remotePatterns: [ + { protocol: 'https', hostname: 'avatars.githubusercontent.com' }, + { protocol: 'https', hostname: 'flagicons.lipis.dev' }, + { protocol: 'https', hostname: 'flowbite.s3.amazonaws.com' }, + ], + }, +}; + +export default withNextIntl(nextConfig); diff --git a/package.json b/package.json new file mode 100644 index 0000000..4ba2d5e --- /dev/null +++ b/package.json @@ -0,0 +1,53 @@ +{ + "name": "opentune-web", + "version": "0.0.0", + "private": true, + "author": { + "name": "Rajnish Kumar", + "email": "RajnishKMehta@proton.me", + "url": "https://github.com/RajnishKMehta" + }, + "packageManager": "pnpm@11.6.0", + "scripts": { + "prepare": "husky", + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint", + "lint:fix": "eslint . --fix", + "format": "prettier . --write", + "format:check": "prettier . --check", + "format:list-diff": "prettier . --list-different" + }, + "lint-staged": { + "*.{js,jsx,ts,tsx,mjs,cjs}": [ + "eslint --fix --max-warnings=0", + "prettier --write" + ], + "*.{json,jsonc,md,mdx,css,scss,yml,yaml,html,toml,svg}": [ + "prettier --write" + ] + }, + "dependencies": { + "lucide-react": "^1.18.0", + "marked": "^18.0.5", + "next": "16.2.9", + "next-intl": "^4.13.0", + "react": "19.2.7", + "react-dom": "19.2.7" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.3", + "@types/node": "^22", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9.39.4", + "eslint-config-next": "^16.2.9", + "husky": "^9.1.7", + "knip": "^6.16.1", + "lint-staged": "^17.0.7", + "prettier": "^3.8.4", + "tailwindcss": "^4.3", + "typescript": "^6" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..72bdfbf --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,5281 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + lucide-react: + specifier: ^1.18.0 + version: 1.18.0(react@19.2.7) + marked: + specifier: ^18.0.5 + version: 18.0.5 + next: + specifier: 16.2.9 + version: 16.2.9(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + next-intl: + specifier: ^4.13.0 + version: 4.13.0(next@16.2.9(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(typescript@6.0.3) + react: + specifier: 19.2.7 + version: 19.2.7 + react-dom: + specifier: 19.2.7 + version: 19.2.7(react@19.2.7) + devDependencies: + '@tailwindcss/postcss': + specifier: ^4.3 + version: 4.3.0 + '@types/node': + specifier: ^22 + version: 22.19.21 + '@types/react': + specifier: ^19 + version: 19.2.17 + '@types/react-dom': + specifier: ^19 + version: 19.2.3(@types/react@19.2.17) + eslint: + specifier: ^9.39.4 + version: 9.39.4(jiti@2.7.0) + eslint-config-next: + specifier: ^16.2.9 + version: 16.2.9(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + husky: + specifier: ^9.1.7 + version: 9.1.7 + knip: + specifier: ^6.16.1 + version: 6.16.1 + lint-staged: + specifier: ^17.0.7 + version: 17.0.7 + prettier: + specifier: ^3.8.4 + version: 3.8.4 + tailwindcss: + specifier: ^4.3 + version: 4.3.0 + typescript: + specifier: ^6 + version: 6.0.3 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/runtime@1.11.0': + resolution: {integrity: sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + 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.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.4': + resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@formatjs/fast-memoize@3.1.6': + resolution: {integrity: sha512-H5aexk1Le7T9TPmscacZ+1pR6CTa2n1wq+HDVGXhH8TzUlQQpeXzZs91dRtmFHrbeNbjPFPfQujUqm7MHgVoXQ==} + + '@formatjs/icu-messageformat-parser@3.5.11': + resolution: {integrity: sha512-NVsuNsc2dUVG9+4HBJ/srScxtA/18LqGgwtop/tuN/OIBjVl6QA+0KhfZQddDD9sEh2LeVjLFPGVU3ixa3blcA==} + + '@formatjs/icu-skeleton-parser@2.1.10': + resolution: {integrity: sha512-XuSva+8ZGawk8VnD5VD6UeH8KarQ/Z022zgjHDoHmlNiAewstXuuzXc0Hk5pGFSdG+nNw5bfJKXqj1ZXHn9yUA==} + + '@formatjs/intl-localematcher@0.8.10': + resolution: {integrity: sha512-P/IC3qws3jH+1fEs+o0RIFgXKRaQlFehjS5W0FPAqdo6hgzawLl+eD0q0JjheQ3XtoOe5n8WSYfX06KQZI/QJA==} + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + 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/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@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@1.1.5': + resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@next/env@16.2.9': + resolution: {integrity: sha512-ki5VxxXfzD/9TDe13wyeTKIjQTAwBVpnr8KhRDUr8ltMUq1/NBpWNT5tiPoxiGl+PHM4X2ahSOiPk6iAimIzPg==} + + '@next/eslint-plugin-next@16.2.9': + resolution: {integrity: sha512-UZi8+YT/MLgTC9nrrn2Xd4lBYv1B7lVmtWHfPcthAI5Tt/C1LuDe6DfmtCtJ+WQod3ksY4VrKSvk3oMVAnL7qw==} + + '@next/swc-darwin-arm64@16.2.9': + resolution: {integrity: sha512-HkfxNYUCmcct0Xsqib5KxqMSHV4AHJq857BNRchyBDs4YS19aHzVfn1kDuBYKqLLQBjXgnkIsjV2Kd4d2wzYhw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@16.2.9': + resolution: {integrity: sha512-7IAtK4MeybpqRV9GRABWEhJ62mOS+rzWOzOTFie4cSEtm12xsoOMJRcECoZx3FHPzFAqN/IJtHqWAFOLfl152w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@16.2.9': + resolution: {integrity: sha512-hBD75iWpUtkL9SmQmcRhmLomn9jgkPzCEkbOcLgHymPEKzv+6ONy13RRiIEz/iEObjkS2Jlb5gYS2XGoS3X4rw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-musl@16.2.9': + resolution: {integrity: sha512-qZTI3pf9SGc/obr8NkQAekBxmp1QK+kVm+VAf3BALLfFAj+1kUhkTxmrWpVos9R/UYIA8AWX2p6cGI5WdwzVUA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-gnu@16.2.9': + resolution: {integrity: sha512-xm0HfRNX+UkH4R3c18ynswjj5o5uEj/7iI9p9omdtTSIsRCzQqkGMA+10nzJ4EHnYC3as65IMhbbl5fWRUWHYg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-musl@16.2.9': + resolution: {integrity: sha512-QumimHkGEG6vM3PfEDWKyKen03NcqLOkeKB1EfcPe7VxzmEiCa4jNnMyBn/US5zcd/VE1CI+O8Ovb3lfjVHfGw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@next/swc-win32-arm64-msvc@16.2.9': + resolution: {integrity: sha512-hzQpKZvw8rAwI6A2uQh6SacCSvNAXaIkPNsWwzqqfRiIMiXMfH936skDhz1OO6KpvdKkJrgHHtqQOq5PIXOvdQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@16.2.9': + resolution: {integrity: sha512-qr2VL3Ce5QrwgO2yh1ujSBawrimjVKX8FGF/cOynmdYKJY0BdHpGVNIRK1tqONB10Vkm25Ub1BD2bkjWs4+96w==} + 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'} + + '@oxc-parser/binding-android-arm-eabi@0.133.0': + resolution: {integrity: sha512-l/44caGse+VpnY9gx0yvvc5QnnG3yG1FO3KZgYvNL1GZrfK86zIwAOgGEVlxDyRymzrU/KHiblPFpevKOmJmUA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxc-parser/binding-android-arm64@0.133.0': + resolution: {integrity: sha512-KUHmPMziLBp4u+zbrLdB7iWS7KshuZe+RAp7ELnY9SI9nNXBZ+dp8fiBqWOxhXqn+FQg3a4UcQhwmsJOKV8Jjg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxc-parser/binding-darwin-arm64@0.133.0': + resolution: {integrity: sha512-q8dWmnU/8ea2tga9w2f1PinQ5rcMPDUGkF64T189b65YMjUomET4oy5oRldOr4AwOQkneOG/Zttnz1Dvrc62wg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxc-parser/binding-darwin-x64@0.133.0': + resolution: {integrity: sha512-cOKeIELIB2bJnCKwqx4Rdj+1Lss/U6uCbLxRySZrhyOOQa1flKhwZFjEHRHxk8fU1NKmhK5OnTdPQ4CpjuFuVw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxc-parser/binding-freebsd-x64@0.133.0': + resolution: {integrity: sha512-OpaSv4pW3KgFrMYQxTaS0aOE4T1DQF3qZE/4B6uqqv1KgPWWd4UQhJALi8PJPX1RRV5K7ThKXRfF7qGg2+3l1A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxc-parser/binding-linux-arm-gnueabihf@0.133.0': + resolution: {integrity: sha512-JGK1wlGrGwxBIlVSF7KWTX1/ru6BEtf28fRROztDRkLfiW+Kxa4onnriezMIiogfn9hVw2KzYcKiLjkLR2ns8A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm-musleabihf@0.133.0': + resolution: {integrity: sha512-yuZO533Ftonxn/iyoqQzURzLQHMspvsIyfiCSNi1t/ER4eIQaR0SsmUOUm5b/lmSig7IWIUa5/BrbEkAPwcilQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm64-gnu@0.133.0': + resolution: {integrity: sha512-hvpbqT5pN2rR+3+xtWeizwfR/aZ0vGceg6TqYMl+ToxMpk9/tmnX7kSvQnfEUkoua8mhogzvIKsAkn0wxgblBA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-arm64-musl@0.133.0': + resolution: {integrity: sha512-wJQGamIosQBoJHW9+S5XxrtKRo3eyJxsnS1XCPrqN0LHi8uw1pTqqTfn3t/NVuvbBg7Pumn4ez9Eidgcn0xbEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxc-parser/binding-linux-ppc64-gnu@0.133.0': + resolution: {integrity: sha512-Koaz32/O5+abIfrNGdyndgRvdOZ9jEf5/z3Ep9h3h2QWpdDiUQpVwgH0OcMXCs+l9aXxPLtkupqyVig9W6FDKw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-riscv64-gnu@0.133.0': + resolution: {integrity: sha512-R4vOjWzxhnNWHnVLeiB6jNuIifdy9vcMXZGPc7StXcxBovI+U2zg1QhZ9o8OjV80oGivs1lX5NfPLzk4IPqlRA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-riscv64-musl@0.133.0': + resolution: {integrity: sha512-iwgBNUTHiMdxARLYuM0SBlnYeb19iw1Ea5M+4ERZupCsBMLArti6FyZ6UfFjJxIiTDr2oW2DGQFxlQVQ/dW9rA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxc-parser/binding-linux-s390x-gnu@0.133.0': + resolution: {integrity: sha512-ZwZNo8FZmB/gVfboQl+wXilBigGl+6nQQs+nITOeAP/HcAOjiHl6XZJL9F/KXNEspODQcbjAiyjUbeCJd9a0fA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-x64-gnu@0.133.0': + resolution: {integrity: sha512-govCvWx1dBlED3uu4qXctxpRcouu9I8Kn+DBktGCl760JtlGJzc9l/OmPJKlYWSbrRqKkMZehNeZ/4Wfma7uSA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-x64-musl@0.133.0': + resolution: {integrity: sha512-ssTlpXD5Mq9uCssDJPzlRWqBt4Y7Zzd9i+XZhWmK/9Y6KUIuAxVYTYiI8lxcGWi0+3/Cz4A8q9UrD4NK9Y2j7g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxc-parser/binding-openharmony-arm64@0.133.0': + resolution: {integrity: sha512-51aByfXhPtLEdWG4a2Ihdw6cPWV1ei1AarALpFdDP8MLWDLE2NuUMgbo3DERR2Kt8fT/ok1GUvBiLxVGke9uUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxc-parser/binding-wasm32-wasi@0.133.0': + resolution: {integrity: sha512-2e16tkKp+wDO2GTAmXfxbBcCmGEaFPIJEIRBBmVKNVXSc8/fJsSIaBGyFTPHM9ST5GNWgJcYIt94rDTks+PLwA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@oxc-parser/binding-win32-arm64-msvc@0.133.0': + resolution: {integrity: sha512-KPTNDKbxH1cglrqTyVeXHb4Pk4oksz8EcE1/v8zqU7N4UXbiHfA/IwtXZ2U77fnRAWBbgVkl/lZbL7o3hRdejg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxc-parser/binding-win32-ia32-msvc@0.133.0': + resolution: {integrity: sha512-Una1bNYv9zCavQrfnDR9wuZVB3itLjCEH4Oz7i6CwAJN/Xq9b+zbbcxmvdkKvvJt4Ngc/MBmIYlbLo3zS4TQ0A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxc-parser/binding-win32-x64-msvc@0.133.0': + resolution: {integrity: sha512-kjBhCiOGSYTwDJQuuZa7a94JbP8htWu7J0X1KwH74kV2K5eYf6eyJRYmkpCDvr0XEL8tMxYI4WU1VekblFCLgg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + + '@oxc-resolver/binding-android-arm-eabi@11.20.0': + resolution: {integrity: sha512-IjfWOXRgJFNdORDl+Uf1aibNgZY2guOD3zmOhx1BGVb/MIiqlFTdmjpQNplSN58lhWehnX4UNqC3QwpUo8pjJg==} + cpu: [arm] + os: [android] + + '@oxc-resolver/binding-android-arm64@11.20.0': + resolution: {integrity: sha512-QqslZAuFQG8Q9xm7JuIn8JUbvywhSBMVhuQHtYW+auirZJloS41oxUUaBXk7uUhZJgp44c5zQLeVvmFaDQB+2Q==} + cpu: [arm64] + os: [android] + + '@oxc-resolver/binding-darwin-arm64@11.20.0': + resolution: {integrity: sha512-MUcavykj2ewlR+kc5arpg4tC2RvzJkUxWtNv74pf7lcNk00GpIpN43vXMj+j6r4eMmfZhlb8hueKoIb8e9kAGQ==} + cpu: [arm64] + os: [darwin] + + '@oxc-resolver/binding-darwin-x64@11.20.0': + resolution: {integrity: sha512-BGB16nRUK5Etiv//ihPyzj8Lj1px0mhh4YIfe0FDf045ywknfSm0GEbiRESpr6Q4K82AvnyaRIhhluHByvS4bg==} + cpu: [x64] + os: [darwin] + + '@oxc-resolver/binding-freebsd-x64@11.20.0': + resolution: {integrity: sha512-JZgtePaqj3qmD5XFHJaSLWzHRxQu0LaPkdoM1KJXYADvAaa83ijXHclV3ej3CueeW0wxfIAbGCZVP45J0CA7uQ==} + cpu: [x64] + os: [freebsd] + + '@oxc-resolver/binding-linux-arm-gnueabihf@11.20.0': + resolution: {integrity: sha512-hOQ/p3ry3v3SchUBXicrrnszaI/UmYzM4wtS4RGfwgVUX7a+HbyQSzJ5aOzu+o6XZkFkS3ZXN4PZAzhOb77OSg==} + cpu: [arm] + os: [linux] + + '@oxc-resolver/binding-linux-arm-musleabihf@11.20.0': + resolution: {integrity: sha512-2ArPksaw0AqeuGBfoS715VF+JvJQAhD2niWgjE5hVO+L+nAfikVQopvngCMX9x4BD8itWoQ3dnikrQyl5Ho5Jg==} + cpu: [arm] + os: [linux] + + '@oxc-resolver/binding-linux-arm64-gnu@11.20.0': + resolution: {integrity: sha512-0bJnmYFp62JdZ4nVMDUZ/C58BCZOCcqgKtnUlp7L9Ojf/czIN+3j72YlLPeWLkzlr6SlYvIQA4SGV/HyO0d+qg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxc-resolver/binding-linux-arm64-musl@11.20.0': + resolution: {integrity: sha512-wKHHzPKZo7Ufhv/Bt6yxT7FOgnIgW4gwXcJUipkShGp68W3wGVqvr1Sr0fY65lN0Oy6y41+g2kIDvkgZaMMUkw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxc-resolver/binding-linux-ppc64-gnu@11.20.0': + resolution: {integrity: sha512-RN8goF7Ie0B79L4i4G6OeBocTgSC56vJbQ65VJje+oXnldVpLnOU7j/AQ/dP94TcCS+Yh6WG8u3Qt4ETteXFNQ==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxc-resolver/binding-linux-riscv64-gnu@11.20.0': + resolution: {integrity: sha512-5l1yU6/xQEqLZRzxqmMxJfWPslpwCmBsdDGaBvABPehxquCXDC7dd7oraNdKSJUMDXSM7VvVj8H2D2FTjU7oWw==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxc-resolver/binding-linux-riscv64-musl@11.20.0': + resolution: {integrity: sha512-xHEvkbgz6UC+A3JOyDQy76LkUaxsNSfIr3/GV8slwZsnuooJiIB34gzJfsyvR4JdCYNUUPsRJc/w/oWkODu+hg==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxc-resolver/binding-linux-s390x-gnu@11.20.0': + resolution: {integrity: sha512-aWPDUUmSeyHvlW+SoEUd+JIJsQhVhu6a5tBpDRMu058naPAchTgAVGCFy35zjbnFlt0i8hLWziff6HX0D3LU4g==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxc-resolver/binding-linux-x64-gnu@11.20.0': + resolution: {integrity: sha512-x2YeSimvhJjKLVD8KSu8f/rqU1potcdEMkApIPJqjZWN7c2Fpt4g2X32WDg1p+XDAmyT7nuQGe0vnhvXeLbH+g==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxc-resolver/binding-linux-x64-musl@11.20.0': + resolution: {integrity: sha512-kcRLEIxpZefeYfLChjpgFf3ilBzRDZ+yobMrpRsQlSrxuFGtm3U6PMU7AaEpMqo3NfDGVyJJseAjnRLzMFHjwQ==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxc-resolver/binding-openharmony-arm64@11.20.0': + resolution: {integrity: sha512-HHcfnApSZGtKhTiHqe8OZruOZe5XuFQH5/E0Yhj3u8fnFvzkM4/k6WjacUf4SvA0SPEAbfbgYmVPuo0VX/fIBQ==} + cpu: [arm64] + os: [openharmony] + + '@oxc-resolver/binding-wasm32-wasi@11.20.0': + resolution: {integrity: sha512-Tn0y1XOFYHNfK1wp1Z5QK8Rcld/bsOwRISQXfqAZ5IBpv8Gz1IvV39fUWNprqNdRizgcvFhOzWwFun2zkJsyBg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@oxc-resolver/binding-win32-arm64-msvc@11.20.0': + resolution: {integrity: sha512-qPi25YNPe4YenS8MgsQU2+bIFHxxpLx1LVna2444cEHqNPhNjvWf9zqj4aWE43H9LpAsTmkkAlA3eL5ElBU3mA==} + cpu: [arm64] + os: [win32] + + '@oxc-resolver/binding-win32-x64-msvc@11.20.0': + resolution: {integrity: sha512-Wb14jWEW8huH6It9F6sXd9vrYmIS7pMrgkU6sxpLxkP+9z+wRgs71hUEhRpcn8FOXAFa27FVWfY2tRpbfTzfLw==} + cpu: [x64] + os: [win32] + + '@parcel/watcher-android-arm64@2.5.6': + resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.6': + resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.6': + resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.6': + resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.6': + resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm-musl@2.5.6': + resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm64-musl@2.5.6': + resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-x64-glibc@2.5.6': + resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-x64-musl@2.5.6': + resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@parcel/watcher-win32-arm64@2.5.6': + resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.6': + resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.6': + resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.6': + resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} + engines: {node: '>= 10.0.0'} + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@schummar/icu-type-parser@1.21.5': + resolution: {integrity: sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==} + + '@swc/core-darwin-arm64@1.15.41': + resolution: {integrity: sha512-kREh6J5paQFvP3i7f/4FbqRNOJREutVFVOkder4GVyCBQ39YmER55cW/y1NNjwrchzFqgYswFn0mMDCqbqKzrw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.15.41': + resolution: {integrity: sha512-N8B56ESFazZAWZyIkecADSPCwlLEinW7QLMEeotCpv4J7VXwfH+OLkmRL8o96UZ+1355fwHxDTS6/wK7yucvkA==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.15.41': + resolution: {integrity: sha512-6XrId2fyle0mS5xxON8rU84mPd2Cq1kDJRj+4BnQKTd7u+2kSA6Ww+JkOP0iTNqOqt9OXhPOEAjBHAuonWcdCg==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.15.41': + resolution: {integrity: sha512-ynLIarxlkVnqHn1D0fKOVht6mNU5ks6lrH+MY3kkS+XFaGGgDxFZVjWKJlkYTKm3RCvBTfA8Ng5fLufXheMRKQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-arm64-musl@1.15.41': + resolution: {integrity: sha512-dXu/5vd4gh8symyhRF+4G7gOPkjmb4pONhh7sl+6GSiW0LOKZlfu5kXmyFbTz9smOT7jgr002qY9b1nujjXt2A==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@swc/core-linux-ppc64-gnu@1.15.41': + resolution: {integrity: sha512-XGO6zVPXoPE0gf/XnI4jBbafNT13AYgoh6ns0JCSdOetI/kqVf0vhpz7NuNgAzZrMVCsmieqjPoTwViDgh4mOQ==} + engines: {node: '>=10'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-s390x-gnu@1.15.41': + resolution: {integrity: sha512-0WUglRwyZtW+iMi7J3iFdrCxreZZIKf4egTwEQfIYRsqFax69A0OrFj+NIoFSE03xBT/IFRrg+S8K6f9Ky+4hA==} + engines: {node: '>=10'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@swc/core-linux-x64-gnu@1.15.41': + resolution: {integrity: sha512-VxkuQK59c0tHm6uJZCUrS3cyA2JhGGfdU6e41SZz0x/JS+4Sm7C1mIc97In14vkZJopEt7yXA2TouCqZDSygEA==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-x64-musl@1.15.41': + resolution: {integrity: sha512-/0qXIu1ZxggLuovLb22vFfKHq2AA4n6Whw5UwmVCHk4pkw7KWnPIQpMCEqUMPsNkFJig7PPp/TSYFu8ZEb2rtQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@swc/core-win32-arm64-msvc@1.15.41': + resolution: {integrity: sha512-Y481sMNZM6rECh9VO4+y26N1lWEDAyxnBZskUf37fl90uHE946VHfmiVQWT0uMFOhyJJFovGTRuF4W82dwewUg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.15.41': + resolution: {integrity: sha512-BAchBD5qeUzy3hiPSLJtaaoSm4blCLyYffOF1bGE4ETcV+OisqjUAwDQMJj++4bTpvMCDzwC+Bj3PmQyBCtscw==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.15.41': + resolution: {integrity: sha512-WOkA+fJ/ViVBQDsSV9JC52NACTe5PhlurA6viASDZGb7HR3KS01ZG7RZ+Bg6SVQFIoq3gSbTsskQVe6EbHFAYw==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.15.41': + resolution: {integrity: sha512-03nQq/082QRJJiOvp3FGbgxTGyyxMxohPTjhk/W9bD2J0tk4ukITI7goOhOO2WbaHn/lsPmo/zf8+DIXhwpgYQ==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '>=0.5.17' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@swc/types@0.1.26': + resolution: {integrity: sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==} + + '@tailwindcss/node@4.3.0': + resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} + + '@tailwindcss/oxide-android-arm64@4.3.0': + resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.0': + resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} + 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.3.0': + resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.0': + resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.3.0': + resolution: {integrity: sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==} + + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@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@22.19.21': + resolution: {integrity: sha512-VMeFBSCKQKmm2swI2kW51SFusDqekC6q9trBCvJ/JliDchFSuoYYKN7yVNjPthP1HKZcx3U1gI/wTcEBjEFKTA==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.17': + resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} + + '@typescript-eslint/eslint-plugin@8.61.0': + resolution: {integrity: sha512-bFNvl9ZczlVb+wR2Akszf3gHfKVj/8WanXaGJ3UstTA7brNKg0cNdk6X1Psu5V7MZ2oQtzZKOEzIUehaoxbDGw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.61.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/parser@8.61.0': + resolution: {integrity: sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.61.0': + resolution: {integrity: sha512-DV42F7MLJO6Rax7SK1yg43tcnEfGUrurSpSxKuVX+a3RCTzBlH3fuxprrOJXKCJGAaw82xXocikJ0uQaqwXgGA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.61.0': + resolution: {integrity: sha512-IWdXFHFSb6mlC3HPc7QsLDm5zYEbUla6trDEHf32D3/dnuUyXd87plScSNXSbm0/RxMvObpI17sv/EDTGrGZkA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.61.0': + resolution: {integrity: sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.61.0': + resolution: {integrity: sha512-TuBiQYIkd97yBfInHCTKVYMbX4kvEmpOEuixIuzCU9p8BGT1SfyyO0d0IfDMbPIHcjn/hWnusUX5e8v5Xg+X8A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.61.0': + resolution: {integrity: sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.61.0': + resolution: {integrity: sha512-42zatd5qSvvcV1JdDBCLxYRznvP4eIHpPoZXdkPFnAmanA4FuZ5dibSnCBggY8hQnqajPpoGjXFdZ7fIJKQnlA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.61.0': + resolution: {integrity: sha512-3bzFt7ImFMW/jVYwJamDoe/dMOdFLSC6pom6rRjdh4SZJEYupyMzem8e7vKZLclLfpHjlwSAXOUxtKxGXUiLqA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.61.0': + resolution: {integrity: sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.12.2': + resolution: {integrity: sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + resolution: {integrity: sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.12.2': + resolution: {integrity: sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + resolution: {integrity: sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + resolution: {integrity: sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + resolution: {integrity: sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} + cpu: [arm64] + os: [openharmony] + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + resolution: {integrity: sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + resolution: {integrity: sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + resolution: {integrity: sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + resolution: {integrity: sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==} + 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.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + 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'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.12.1: + resolution: {integrity: sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==} + 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==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + baseline-browser-mapping@2.10.36: + resolution: {integrity: sha512-lVq/Df7LXlO79MVaaUHztSwWiG9oXoWHlgvNS51v8Dpd4+G4/VIy6qYePTw31nAVls33nUtnfezYeLkYAak9dg==} + engines: {node: '>=6.0.0'} + hasBin: true + + brace-expansion@1.1.15: + resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==} + + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + engines: {node: 18 || 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + 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.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} + 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.30001799: + resolution: {integrity: sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-truncate@5.2.0: + resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==} + engines: {node: '>=20'} + + 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==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + 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.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + 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.372: + resolution: {integrity: sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==} + + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enhanced-resolve@5.24.0: + resolution: {integrity: sha512-SkE2t82KlkkxQRVMVLAGKxLfORGQfrkx5dkj+vlgXRVNEdPc4eZcR+J/Fvj8C+yKSFH5L0q3NFlyufOVQnCcYQ==} + engines: {node: '>=10.13.0'} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + es-abstract@1.24.2: + resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} + 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.3.3: + resolution: {integrity: sha512-0PuBxFi+4uPanB97iDxCLWuHeYud2FALrw5HFZGtAF38UpJDbDC8frwp2cnDyae692CQ0dou60UwWfhgsa4U/g==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + 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@16.2.9: + resolution: {integrity: sha512-olGtBrs07bQchpaJWeqbk9GaMoU0oGmN/pYNEBXSbfgKngb5uHnPe37X6tVeh6DJfaWFQildvinGEOrolo5fmw==} + peerDependencies: + eslint: '>=9.0.0' + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + + eslint-import-resolver-node@0.3.10: + resolution: {integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==} + + 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.13.0: + resolution: {integrity: sha512-bLohSkT6469rRs8czj0tLTD8vaeIS/whvPRJVjDr7IuoTT1k5DYDERlNycjDj/HkOlvQdYurmfZ/g3fG5bgeLQ==} + 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@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.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-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.4: + resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} + 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.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + 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'} + + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + + 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-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.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fd-package-json@2.0.0: + resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==} + + 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.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + formatly@0.3.0: + resolution: {integrity: sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==} + engines: {node: '>=18.3.0'} + hasBin: true + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.2.0: + resolution: {integrity: sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + + 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.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + + 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'} + + globals@16.4.0: + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + 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==} + + 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.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + + husky@9.1.7: + resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} + engines: {node: '>=18'} + hasBin: true + + icu-minify@4.13.0: + resolution: {integrity: sha512-SIFMeUHZJjzS5RvIGvybKvWoHjDm9cGVEs2EpJ8PmywOdJLWyblPm7TdPLLoUtkJtwQD7iGhl2WMptZ+N0on+w==} + + 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'} + + intl-messageformat@11.2.8: + resolution: {integrity: sha512-l323RCl3qJDVQ8U9j74ut/hVMdg3VPsOHpVMDvFfz9qiq4dPO5ooVYFNVUzzrpgG39a+RLzcXyJb8VFgIU+tUA==} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + 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.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} + 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-document.all@1.0.0: + resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} + 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-fullwidth-code-point@5.1.0: + resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + engines: {node: '>=18'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + 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.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.2.0: + resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + 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 + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + 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==} + + knip@6.16.1: + resolution: {integrity: sha512-TKMn1rxgH6h9vXR9Y0B+Cq7AdPTr9EI02IwoT65NzqYUkvoDQAaJ/aPybiFpAhZ1px6cNYYwXf86iHkBgzCo9w==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + 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-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + lint-staged@17.0.7: + resolution: {integrity: sha512-JrSobt+tW3rH8IOMi8tDZd3foorM5yPEkLD/V2NxobgHrFfHWGee4MOLVuZeScgxftEwbHrPHIFA/ZL+nUJeuA==} + engines: {node: '>=22.22.1'} + hasBin: true + + listr2@10.2.1: + resolution: {integrity: sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q==} + engines: {node: '>=22.13.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@1.18.0: + resolution: {integrity: sha512-LZDb7H/0YfM+RJncD0hDQRCAu+vSGODqpe35TuVI8EuXaRjkczbsx7p8dY4J87F/MUSj6bpYqeI8nw8qXaAdmA==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + marked@18.0.5: + resolution: {integrity: sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w==} + engines: {node: '>= 20'} + hasBin: true + + 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'} + + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + next-intl-swc-plugin-extractor@4.13.0: + resolution: {integrity: sha512-6S/fJI0KXvLCL8nhBo9P8eGaJPzmwJBTCzX0NaUIj0VyU8U89d//T+vjMLdNIXl5MlLaYH7B9MbAjb8Mvu+tqQ==} + + next-intl@4.13.0: + resolution: {integrity: sha512-OvNq2v5XLx4EkQOsAhVE9g+6zdb83XHusADCXXtIW4LILYnjEVaeINdr1lkVWKSjzwNUiMSlH5N4K0OQTRiv6A==} + peerDependencies: + next: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + next@16.2.9: + resolution: {integrity: sha512-MEOJiq/UvuezAdqVSceHbqDgZt1kDw2tpGVOlsdIoJsQdbN2JY2hpVG4xnXGkbdJUOEWhnRfiu/O4Hpc9Juwww==} + engines: {node: '>=20.9.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-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + node-exports-info@1.6.0: + resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} + engines: {node: '>= 0.4'} + + node-releases@2.0.47: + resolution: {integrity: sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==} + engines: {node: '>=18'} + + 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'} + + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + 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'} + + oxc-parser@0.133.0: + resolution: {integrity: sha512-661RSx+ZcjBmjBYid+Fpp/2F5EbtildpeoZh5HdgnGs+jZ03nqQEQW8yGkt4BGyOC3OMPDQQRl8M5kqD2/g6jw==} + engines: {node: ^20.19.0 || >=22.12.0} + + oxc-resolver@11.20.0: + resolution: {integrity: sha512-CblytBiV/a/ZXY34dsVU2NxhIOxMXst8CvDCtyBelVITgd7PLrKzbEbA6oKLdPjvDKDzCiW48qzmzZ+mYaqn+g==} + + 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.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + po-parser@2.1.1: + resolution: {integrity: sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@3.8.4: + resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==} + engines: {node: '>=14'} + hasBin: true + + 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.2.7: + resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} + peerDependencies: + react: ^19.2.7 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react@19.2.7: + resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} + 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@2.0.0-next.7: + resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} + engines: {node: '>= 0.4'} + hasBin: true + + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.4: + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} + 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.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.8.4: + resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} + 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.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + 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.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + 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.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slice-ansi@7.1.2: + resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + engines: {node: '>=18'} + + slice-ansi@8.0.0: + resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} + engines: {node: '>=20'} + + smol-toml@1.6.1: + resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==} + engines: {node: '>= 18'} + + 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-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string-width@8.2.1: + resolution: {integrity: sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==} + engines: {node: '>=20'} + + 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.11: + resolution: {integrity: sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.10: + resolution: {integrity: sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + 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'} + + strip-json-comments@5.0.3: + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} + engines: {node: '>=14.16'} + + 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.3.0: + resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + 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.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + 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.8: + resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} + engines: {node: '>= 0.4'} + + typescript-eslint@8.61.0: + resolution: {integrity: sha512-8y31Rd0eGTrDKqhy6vT0HtzhN+YLjQizwX3aA3hPXP/ynSfnrBXcQY5IzsP9/DM7+klX4IUncZZjkchP0z+rUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + + unbash@3.0.0: + resolution: {integrity: sha512-FeFPZ/WFT0mbRCuydiZzpPFlrYN8ZUpphQKoq4EeElVIYjYyGzPMxQR/simUwCOJIyVhpFk4RbtyO7RuMpMnHA==} + engines: {node: '>=14'} + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unrs-resolver@1.12.2: + resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-intl@4.13.0: + resolution: {integrity: sha512-fAFDrWaASxlhXOipcOyb5VDD+YONqj6+8O8EcG/J7RBoOUF3A8YahRWLN+mBxYMrlMQB8N6Voqk5X+YC+HSL0A==} + peerDependencies: + react: ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 + + walk-up-path@4.0.0: + resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} + engines: {node: 20 || >=22} + + 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.22: + resolution: {integrity: sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==} + 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'} + + wrap-ansi@10.0.0: + resolution: {integrity: sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==} + engines: {node: '>=20'} + + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.7': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': + dependencies: + eslint: 9.39.4(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.5': + dependencies: + ajv: 6.15.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.2.0 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.4': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@formatjs/fast-memoize@3.1.6': {} + + '@formatjs/icu-messageformat-parser@3.5.11': + dependencies: + '@formatjs/icu-skeleton-parser': 2.1.10 + + '@formatjs/icu-skeleton-parser@2.1.10': {} + + '@formatjs/intl-localematcher@0.8.10': + dependencies: + '@formatjs/fast-memoize': 3.1.6 + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.0 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@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@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true + + '@next/env@16.2.9': {} + + '@next/eslint-plugin-next@16.2.9': + dependencies: + fast-glob: 3.3.1 + + '@next/swc-darwin-arm64@16.2.9': + optional: true + + '@next/swc-darwin-x64@16.2.9': + optional: true + + '@next/swc-linux-arm64-gnu@16.2.9': + optional: true + + '@next/swc-linux-arm64-musl@16.2.9': + optional: true + + '@next/swc-linux-x64-gnu@16.2.9': + optional: true + + '@next/swc-linux-x64-musl@16.2.9': + optional: true + + '@next/swc-win32-arm64-msvc@16.2.9': + optional: true + + '@next/swc-win32-x64-msvc@16.2.9': + 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.20.1 + + '@nolyfill/is-core-module@1.0.39': {} + + '@oxc-parser/binding-android-arm-eabi@0.133.0': + optional: true + + '@oxc-parser/binding-android-arm64@0.133.0': + optional: true + + '@oxc-parser/binding-darwin-arm64@0.133.0': + optional: true + + '@oxc-parser/binding-darwin-x64@0.133.0': + optional: true + + '@oxc-parser/binding-freebsd-x64@0.133.0': + optional: true + + '@oxc-parser/binding-linux-arm-gnueabihf@0.133.0': + optional: true + + '@oxc-parser/binding-linux-arm-musleabihf@0.133.0': + optional: true + + '@oxc-parser/binding-linux-arm64-gnu@0.133.0': + optional: true + + '@oxc-parser/binding-linux-arm64-musl@0.133.0': + optional: true + + '@oxc-parser/binding-linux-ppc64-gnu@0.133.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-gnu@0.133.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-musl@0.133.0': + optional: true + + '@oxc-parser/binding-linux-s390x-gnu@0.133.0': + optional: true + + '@oxc-parser/binding-linux-x64-gnu@0.133.0': + optional: true + + '@oxc-parser/binding-linux-x64-musl@0.133.0': + optional: true + + '@oxc-parser/binding-openharmony-arm64@0.133.0': + optional: true + + '@oxc-parser/binding-wasm32-wasi@0.133.0': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@oxc-parser/binding-win32-arm64-msvc@0.133.0': + optional: true + + '@oxc-parser/binding-win32-ia32-msvc@0.133.0': + optional: true + + '@oxc-parser/binding-win32-x64-msvc@0.133.0': + optional: true + + '@oxc-project/types@0.133.0': {} + + '@oxc-resolver/binding-android-arm-eabi@11.20.0': + optional: true + + '@oxc-resolver/binding-android-arm64@11.20.0': + optional: true + + '@oxc-resolver/binding-darwin-arm64@11.20.0': + optional: true + + '@oxc-resolver/binding-darwin-x64@11.20.0': + optional: true + + '@oxc-resolver/binding-freebsd-x64@11.20.0': + optional: true + + '@oxc-resolver/binding-linux-arm-gnueabihf@11.20.0': + optional: true + + '@oxc-resolver/binding-linux-arm-musleabihf@11.20.0': + optional: true + + '@oxc-resolver/binding-linux-arm64-gnu@11.20.0': + optional: true + + '@oxc-resolver/binding-linux-arm64-musl@11.20.0': + optional: true + + '@oxc-resolver/binding-linux-ppc64-gnu@11.20.0': + optional: true + + '@oxc-resolver/binding-linux-riscv64-gnu@11.20.0': + optional: true + + '@oxc-resolver/binding-linux-riscv64-musl@11.20.0': + optional: true + + '@oxc-resolver/binding-linux-s390x-gnu@11.20.0': + optional: true + + '@oxc-resolver/binding-linux-x64-gnu@11.20.0': + optional: true + + '@oxc-resolver/binding-linux-x64-musl@11.20.0': + optional: true + + '@oxc-resolver/binding-openharmony-arm64@11.20.0': + optional: true + + '@oxc-resolver/binding-wasm32-wasi@11.20.0': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@oxc-resolver/binding-win32-arm64-msvc@11.20.0': + optional: true + + '@oxc-resolver/binding-win32-x64-msvc@11.20.0': + optional: true + + '@parcel/watcher-android-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-x64@2.5.6': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.6': + optional: true + + '@parcel/watcher-win32-arm64@2.5.6': + optional: true + + '@parcel/watcher-win32-ia32@2.5.6': + optional: true + + '@parcel/watcher-win32-x64@2.5.6': + optional: true + + '@parcel/watcher@2.5.6': + dependencies: + detect-libc: 2.1.2 + is-glob: 4.0.3 + node-addon-api: 7.1.1 + picomatch: 4.0.4 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.6 + '@parcel/watcher-darwin-arm64': 2.5.6 + '@parcel/watcher-darwin-x64': 2.5.6 + '@parcel/watcher-freebsd-x64': 2.5.6 + '@parcel/watcher-linux-arm-glibc': 2.5.6 + '@parcel/watcher-linux-arm-musl': 2.5.6 + '@parcel/watcher-linux-arm64-glibc': 2.5.6 + '@parcel/watcher-linux-arm64-musl': 2.5.6 + '@parcel/watcher-linux-x64-glibc': 2.5.6 + '@parcel/watcher-linux-x64-musl': 2.5.6 + '@parcel/watcher-win32-arm64': 2.5.6 + '@parcel/watcher-win32-ia32': 2.5.6 + '@parcel/watcher-win32-x64': 2.5.6 + + '@rtsao/scc@1.1.0': {} + + '@schummar/icu-type-parser@1.21.5': {} + + '@swc/core-darwin-arm64@1.15.41': + optional: true + + '@swc/core-darwin-x64@1.15.41': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.15.41': + optional: true + + '@swc/core-linux-arm64-gnu@1.15.41': + optional: true + + '@swc/core-linux-arm64-musl@1.15.41': + optional: true + + '@swc/core-linux-ppc64-gnu@1.15.41': + optional: true + + '@swc/core-linux-s390x-gnu@1.15.41': + optional: true + + '@swc/core-linux-x64-gnu@1.15.41': + optional: true + + '@swc/core-linux-x64-musl@1.15.41': + optional: true + + '@swc/core-win32-arm64-msvc@1.15.41': + optional: true + + '@swc/core-win32-ia32-msvc@1.15.41': + optional: true + + '@swc/core-win32-x64-msvc@1.15.41': + optional: true + + '@swc/core@1.15.41': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.26 + optionalDependencies: + '@swc/core-darwin-arm64': 1.15.41 + '@swc/core-darwin-x64': 1.15.41 + '@swc/core-linux-arm-gnueabihf': 1.15.41 + '@swc/core-linux-arm64-gnu': 1.15.41 + '@swc/core-linux-arm64-musl': 1.15.41 + '@swc/core-linux-ppc64-gnu': 1.15.41 + '@swc/core-linux-s390x-gnu': 1.15.41 + '@swc/core-linux-x64-gnu': 1.15.41 + '@swc/core-linux-x64-musl': 1.15.41 + '@swc/core-win32-arm64-msvc': 1.15.41 + '@swc/core-win32-ia32-msvc': 1.15.41 + '@swc/core-win32-x64-msvc': 1.15.41 + + '@swc/counter@0.1.3': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@swc/types@0.1.26': + dependencies: + '@swc/counter': 0.1.3 + + '@tailwindcss/node@4.3.0': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.24.0 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.0 + + '@tailwindcss/oxide-android-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide@4.3.0': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-x64': 4.3.0 + '@tailwindcss/oxide-freebsd-x64': 4.3.0 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.0 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-x64-musl': 4.3.0 + '@tailwindcss/oxide-wasm32-wasi': 4.3.0 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 + + '@tailwindcss/postcss@4.3.0': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.3.0 + '@tailwindcss/oxide': 4.3.0 + postcss: 8.5.15 + tailwindcss: 4.3.0 + + '@tybys/wasm-util@0.10.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/estree@1.0.9': {} + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/node@22.19.21': + dependencies: + undici-types: 6.21.0 + + '@types/react-dom@19.2.3(@types/react@19.2.17)': + dependencies: + '@types/react': 19.2.17 + + '@types/react@19.2.17': + dependencies: + csstype: 3.2.3 + + '@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/type-utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.61.0 + eslint: 9.39.4(jiti@2.7.0) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.61.0 + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.61.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.61.0(typescript@6.0.3) + '@typescript-eslint/types': 8.61.0 + debug: 4.4.3 + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.61.0': + dependencies: + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/visitor-keys': 8.61.0 + + '@typescript-eslint/tsconfig-utils@8.61.0(typescript@6.0.3)': + dependencies: + typescript: 6.0.3 + + '@typescript-eslint/type-utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.61.0': {} + + '@typescript-eslint/typescript-estree@8.61.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/project-service': 8.61.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.61.0(typescript@6.0.3) + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/visitor-keys': 8.61.0 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.8.4 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3) + eslint: 9.39.4(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.61.0': + dependencies: + '@typescript-eslint/types': 8.61.0 + eslint-visitor-keys: 5.0.1 + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + optional: true + + '@unrs/resolver-binding-android-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + optional: true + + acorn-jsx@5.3.2(acorn@8.17.0): + dependencies: + acorn: 8.17.0 + + acorn@8.17.0: {} + + ajv@6.15.0: + 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-escapes@7.3.0: + dependencies: + environment: 1.1.0 + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + 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.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + 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.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + 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.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + 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: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.12.1: {} + + axobject-query@4.1.0: {} + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.10.36: {} + + brace-expansion@1.1.15: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@5.0.6: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.36 + caniuse-lite: 1.0.30001799 + electron-to-chromium: 1.5.372 + node-releases: 2.0.47 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.9: + 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.30001799: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-truncate@5.2.0: + dependencies: + slice-ansi: 8.0.0 + string-width: 8.2.1 + + client-only@0.0.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.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.1.2: {} + + 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.372: {} + + emoji-regex@10.6.0: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.24.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + environment@1.1.0: {} + + es-abstract@1.24.2: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + 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.2 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.2.0 + 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.4 + 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.4 + 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.11 + string.prototype.trimend: 1.0.10 + 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.8 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.22 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.3.3: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + 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 + math-intrinsics: 1.1.0 + + es-object-atoms@1.1.2: + 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.4 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.4 + + 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@16.2.9(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3): + dependencies: + '@next/eslint-plugin-next': 16.2.9 + eslint: 9.39.4(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react-hooks: 7.1.1(eslint@9.39.4(jiti@2.7.0)) + globals: 16.4.0 + typescript-eslint: 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-import-resolver-node@0.3.10: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.2 + resolve: 2.0.0-next.7 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + get-tsconfig: 4.14.0 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.17 + unrs-resolver: 1.12.2 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.13.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + eslint: 9.39.4(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): + 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.39.4(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + hasown: 2.0.4 + is-core-module: 2.16.2 + is-glob: 4.0.3 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.10 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.4(jiti@2.7.0)): + 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.12.1 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.39.4(jiti@2.7.0) + hasown: 2.0.4 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-react-hooks@7.1.1(eslint@9.39.4(jiti@2.7.0)): + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.7 + eslint: 9.39.4(jiti@2.7.0) + hermes-parser: 0.25.1 + zod: 4.4.3 + zod-validation-error: 4.0.2(zod@4.4.3) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.7.0)): + 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.3.3 + eslint: 9.39.4(jiti@2.7.0) + estraverse: 5.3.0 + hasown: 2.0.4 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.5 + 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.7 + 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-visitor-keys@5.0.1: {} + + eslint@9.39.4(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.39.4 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + 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.7.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.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + eventemitter3@5.0.4: {} + + 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-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fd-package-json@2.0.0: + dependencies: + walk-up-path: 4.0.0 + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + 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.4.2 + keyv: 4.5.4 + + flatted@3.4.2: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + formatly@0.3.0: + dependencies: + fd-package-json: 2.0.0 + + function-bind@1.1.2: {} + + function.prototype.name@1.2.0: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + es-define-property: 1.0.1 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + hasown: 2.0.4 + is-callable: 1.2.7 + is-document.all: 1.0.0 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + gensync@1.0.0-beta.2: {} + + get-east-asian-width@1.6.0: {} + + 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.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + 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.14.0: + 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: {} + + globals@16.4.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + 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.4: + dependencies: + function-bind: 1.1.2 + + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + husky@9.1.7: {} + + icu-minify@4.13.0: + dependencies: + '@formatjs/icu-messageformat-parser': 3.5.11 + + 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.4 + side-channel: 1.1.1 + + intl-messageformat@11.2.8: + dependencies: + '@formatjs/fast-memoize': 3.1.6 + '@formatjs/icu-messageformat-parser': 3.5.11 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + 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.8.4 + + is-callable@1.2.7: {} + + is-core-module@2.16.2: + dependencies: + hasown: 2.0.4 + + 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-document.all@1.0.0: + dependencies: + call-bound: 1.0.4 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.6.0 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + 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.4 + + 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.22 + + 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.2 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jiti@2.7.0: {} + + js-tokens@4.0.0: {} + + js-yaml@4.2.0: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + 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 + + json5@2.2.3: {} + + 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 + + knip@6.16.1: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + formatly: 0.3.0 + get-tsconfig: 4.14.0 + jiti: 2.7.0 + oxc-parser: 0.133.0 + oxc-resolver: 11.20.0 + picomatch: 4.0.4 + smol-toml: 1.6.1 + strip-json-comments: 5.0.3 + tinyglobby: 0.2.17 + unbash: 3.0.0 + yaml: 2.9.0 + zod: 4.4.3 + + 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-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + lint-staged@17.0.7: + dependencies: + listr2: 10.2.1 + picomatch: 4.0.4 + string-argv: 0.3.2 + tinyexec: 1.2.4 + optionalDependencies: + yaml: 2.9.0 + + listr2@10.2.1: + dependencies: + cli-truncate: 5.2.0 + eventemitter3: 5.0.4 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 10.0.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.3.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.2 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@1.18.0(react@19.2.7): + dependencies: + react: 19.2.7 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + marked@18.0.5: {} + + math-intrinsics@1.1.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + mimic-function@5.0.1: {} + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.6 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.15 + + minimist@1.2.8: {} + + ms@2.1.3: {} + + nanoid@3.3.12: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + negotiator@1.0.0: {} + + next-intl-swc-plugin-extractor@4.13.0: {} + + next-intl@4.13.0(next@16.2.9(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(typescript@6.0.3): + dependencies: + '@formatjs/intl-localematcher': 0.8.10 + '@parcel/watcher': 2.5.6 + '@swc/core': 1.15.41 + icu-minify: 4.13.0 + negotiator: 1.0.0 + next: 16.2.9(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + next-intl-swc-plugin-extractor: 4.13.0 + po-parser: 2.1.1 + react: 19.2.7 + use-intl: 4.13.0(react@19.2.7) + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - '@swc/helpers' + + next@16.2.9(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + '@next/env': 16.2.9 + '@swc/helpers': 0.5.15 + baseline-browser-mapping: 2.10.36 + caniuse-lite: 1.0.30001799 + postcss: 8.4.31 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + styled-jsx: 5.1.6(@babel/core@7.29.7)(react@19.2.7) + optionalDependencies: + '@next/swc-darwin-arm64': 16.2.9 + '@next/swc-darwin-x64': 16.2.9 + '@next/swc-linux-arm64-gnu': 16.2.9 + '@next/swc-linux-arm64-musl': 16.2.9 + '@next/swc-linux-x64-gnu': 16.2.9 + '@next/swc-linux-x64-musl': 16.2.9 + '@next/swc-win32-arm64-msvc': 16.2.9 + '@next/swc-win32-x64-msvc': 16.2.9 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-addon-api@7.1.1: {} + + node-exports-info@1.6.0: + dependencies: + array.prototype.flatmap: 1.3.3 + es-errors: 1.3.0 + object.entries: 1.1.9 + semver: 6.3.1 + + node-releases@2.0.47: {} + + 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.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.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 + + oxc-parser@0.133.0: + dependencies: + '@oxc-project/types': 0.133.0 + optionalDependencies: + '@oxc-parser/binding-android-arm-eabi': 0.133.0 + '@oxc-parser/binding-android-arm64': 0.133.0 + '@oxc-parser/binding-darwin-arm64': 0.133.0 + '@oxc-parser/binding-darwin-x64': 0.133.0 + '@oxc-parser/binding-freebsd-x64': 0.133.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.133.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.133.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.133.0 + '@oxc-parser/binding-linux-arm64-musl': 0.133.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.133.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.133.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.133.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.133.0 + '@oxc-parser/binding-linux-x64-gnu': 0.133.0 + '@oxc-parser/binding-linux-x64-musl': 0.133.0 + '@oxc-parser/binding-openharmony-arm64': 0.133.0 + '@oxc-parser/binding-wasm32-wasi': 0.133.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.133.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.133.0 + '@oxc-parser/binding-win32-x64-msvc': 0.133.0 + + oxc-resolver@11.20.0: + optionalDependencies: + '@oxc-resolver/binding-android-arm-eabi': 11.20.0 + '@oxc-resolver/binding-android-arm64': 11.20.0 + '@oxc-resolver/binding-darwin-arm64': 11.20.0 + '@oxc-resolver/binding-darwin-x64': 11.20.0 + '@oxc-resolver/binding-freebsd-x64': 11.20.0 + '@oxc-resolver/binding-linux-arm-gnueabihf': 11.20.0 + '@oxc-resolver/binding-linux-arm-musleabihf': 11.20.0 + '@oxc-resolver/binding-linux-arm64-gnu': 11.20.0 + '@oxc-resolver/binding-linux-arm64-musl': 11.20.0 + '@oxc-resolver/binding-linux-ppc64-gnu': 11.20.0 + '@oxc-resolver/binding-linux-riscv64-gnu': 11.20.0 + '@oxc-resolver/binding-linux-riscv64-musl': 11.20.0 + '@oxc-resolver/binding-linux-s390x-gnu': 11.20.0 + '@oxc-resolver/binding-linux-x64-gnu': 11.20.0 + '@oxc-resolver/binding-linux-x64-musl': 11.20.0 + '@oxc-resolver/binding-openharmony-arm64': 11.20.0 + '@oxc-resolver/binding-wasm32-wasi': 11.20.0 + '@oxc-resolver/binding-win32-arm64-msvc': 11.20.0 + '@oxc-resolver/binding-win32-x64-msvc': 11.20.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.2: {} + + picomatch@4.0.4: {} + + po-parser@2.1.1: {} + + possible-typed-array-names@1.1.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier@3.8.4: {} + + 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.2.7(react@19.2.7): + dependencies: + react: 19.2.7 + scheduler: 0.27.0 + + react-is@16.13.1: {} + + react@19.2.7: {} + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + 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.9 + 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@2.0.0-next.7: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + node-exports-info: 1.6.0 + object-keys: 1.1.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + reusify@1.1.0: {} + + rfdc@1.4.1: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.4: + dependencies: + call-bind: 1.0.9 + 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.27.0: {} + + semver@6.3.1: {} + + semver@7.8.4: {} + + 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.2 + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.4 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.1: + 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.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@4.1.0: {} + + slice-ansi@7.1.2: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + + slice-ansi@8.0.0: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + + smol-toml@1.6.1: {} + + 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-argv@0.3.2: {} + + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 + + string-width@8.2.1: + dependencies: + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + 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.1 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.trim@1.2.11: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + has-property-descriptors: 1.0.2 + safe-regex-test: 1.1.0 + + string.prototype.trimend@1.0.10: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + + strip-bom@3.0.0: {} + + strip-json-comments@3.1.1: {} + + strip-json-comments@5.0.3: {} + + styled-jsx@5.1.6(@babel/core@7.29.7)(react@19.2.7): + dependencies: + client-only: 0.0.1 + react: 19.2.7 + optionalDependencies: + '@babel/core': 7.29.7 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tailwindcss@4.3.0: {} + + tapable@2.3.3: {} + + tinyexec@1.2.4: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@2.5.0(typescript@6.0.3): + dependencies: + typescript: 6.0.3 + + 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.9 + 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.9 + 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.8: + dependencies: + call-bind: 1.0.9 + 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-eslint@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.61.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + eslint: 9.39.4(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + typescript@6.0.3: {} + + unbash@3.0.0: {} + + 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@6.21.0: {} + + unrs-resolver@1.12.2: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.12.2 + '@unrs/resolver-binding-android-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-x64': 1.12.2 + '@unrs/resolver-binding-freebsd-x64': 1.12.2 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-arm64-musl': 1.12.2 + '@unrs/resolver-binding-linux-loong64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-loong64-musl': 1.12.2 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-musl': 1.12.2 + '@unrs/resolver-binding-linux-s390x-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-musl': 1.12.2 + '@unrs/resolver-binding-openharmony-arm64': 1.12.2 + '@unrs/resolver-binding-wasm32-wasi': 1.12.2 + '@unrs/resolver-binding-win32-arm64-msvc': 1.12.2 + '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 + '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-intl@4.13.0(react@19.2.7): + dependencies: + '@formatjs/fast-memoize': 3.1.6 + '@schummar/icu-type-parser': 1.21.5 + icu-minify: 4.13.0 + intl-messageformat: 11.2.8 + react: 19.2.7 + + walk-up-path@4.0.0: {} + + 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.2.0 + 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.2 + 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.22 + + 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.22: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + 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: {} + + wrap-ansi@10.0.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 8.2.1 + strip-ansi: 7.2.0 + + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.2.0 + + yallist@3.1.1: {} + + yaml@2.9.0: {} + + yocto-queue@0.1.0: {} + + zod-validation-error@4.0.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..4e6e06b --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,22 @@ +allowBuilds: + '@parcel/watcher': true + '@swc/core': true + sharp: true + unrs-resolver: true +ignoredBuiltDependencies: + - sharp + - unrs-resolver +minimumReleaseAgeExclude: + - '@next/env@16.2.9' + - '@next/eslint-plugin-next@16.2.9' + - '@next/swc-darwin-arm64@16.2.9' + - '@next/swc-darwin-x64@16.2.9' + - '@next/swc-linux-arm64-gnu@16.2.9' + - '@next/swc-linux-arm64-musl@16.2.9' + - '@next/swc-linux-x64-gnu@16.2.9' + - '@next/swc-linux-x64-musl@16.2.9' + - '@next/swc-win32-arm64-msvc@16.2.9' + - '@next/swc-win32-x64-msvc@16.2.9' + - eslint-config-next@16.2.9 + - next@16.2.9 + - lucide-react@1.18.0 diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000..297374d --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; + +export default config; diff --git a/pt_BR.html b/pt_BR.html deleted file mode 100644 index 504f04e..0000000 --- a/pt_BR.html +++ /dev/null @@ -1,742 +0,0 @@ - - - - - - - - - - - - - - OpenTune - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Selecionar Idioma

- -
- - -
- - - -
-
-
- warning -
-

Aviso de Redirecionamento

-
-
-
-

Você será redirecionado para fora do OpenTune Web para uma - demonstração externa fornecida pelo Appetize.io.

-
-
- - -
-
- - - - - - - - -
- - -
- -
-
-
-
- -
- -
- -
- code - Dev By Arthur Dev Studio -
- -

OpenTune

-

- Um cliente do YouTube Music com Material Design 3, para Android. -

- -
- - download - Baixar APK - - -
-
- - -
-
- Prévia do App OpenTune -
-
-
-
-
-
- - -
-
-
-

Recursos

-

- Descubra todos os recursos que fazem do OpenTune o melhor cliente para sua música. -

-
- -
- -
-
- music_note -
-

Cliente do YouTube Music com Material Design 3 -

-

Oferece uma experiência moderna e - elegante do YouTube Music no Android, com uma interface intuitiva e otimizada.

-
- -
-
- palette -
-

Design Moderno e Atraente

-

Baseado no Material Design 3, com - cores vibrantes, tipografia moderna e transições suaves.

-
- -
-
- settings -
-

Interface Intuitiva e Personalizável

-

Interface simplificada para acesso - rápido a todas as funcionalidades, com opções de personalização.

-
- -
-
- search -
-

Explore e Descubra Música

-

Acesso a um vasto catálogo musical - com busca avançada e recomendações inteligentes.

-
- -
-
- volume_up -
-

Reprodução de Alta Qualidade

-

Música de alta qualidade, otimizada - para diferentes dispositivos e condições de rede.

-
- -
-
- playlist_add -
-

Playlists e Downloads

-

Crie e organize playlists, - e baixe músicas para ouvir offline.

-
- -
-
- sync -
-

Integração com o YouTube Music

-

Sincronize sua conta do YouTube Music - para acessar suas bibliotecas e receber notificações.

-
- -
-
- build -
-

Funcionalidades Avançadas

-

Controle de reprodução por voz e - gestos, com suporte para Chromecast e Bluetooth.

-
- -
-
- folder -
-

Gerenciamento Eficiente da Biblioteca

-

Organize sua música com - ferramentas avançadas de filtragem e categorização.

-
- -
-
- translate -
-

Suporte Multilíngue

-

Disponível em vários idiomas - com traduções precisas e localização culturalmente relevante.

-
- -
-
- update -
-

Atualizações Contínuas

-

Atualizações regulares com novas - funcionalidades, melhorias de segurança e otimização.

-
- -
-
- headphones -
-

Experiência do Usuário Otimizada

-

Navegação intuitiva e desempenho - ágil com uma interface amigável que melhora a experiência.

-
-
-
-
- - -
-
-
- IMPULSIONADO - PELA COMUNIDADE -

Código Aberto no Coração

-

O OpenTune é construído por amantes de música - para amantes de música. Contribua, personalize e nos ajude a construir o melhor reprodutor - de código aberto para Android.

- -
- -
-
-
- -
-
-

Arturo254

-

Desenvolvedor Principal

-
-
-
-
- verified -
-
-

Última versão estável

-

Carregando...

-
-
-
-
-
-
-
- - -
-
- -
-
-
-

A Interface

-

Um vislumbre da experiência do OpenTune.

-
- -
-
- - - -
-
- - -
-
-
-
- support_agent -
-

Precisa de Ajuda?

-

- Envie uma solicitação ou relate um problema diretamente à equipe de desenvolvimento. -

- - send - Solicitar Ajuda - -
-
-
- - -
-
-
-

Downloads

-

- Baixe a versão mais recente do OpenTune para sua plataforma. -

-
- -
- - -
-
-
- android -
-
-

Android

-

Baixe a última versão estável.

-
-
- -
- Versão Estável - Carregando... -
- -
- - -
- -
- - download - Baixar APK - -

Requer Android 8.0+

-
-
- - - - -
-
-
-
- laptop_windows -
-
-

Windows

-

O desenvolvimento está fechado no momento. -

-
-
- -
- Fechado - Indisponível -
- -
- - list_alt - Ver Alterações - - - history - Versões Anteriores - -
- -
- -
-
-
- -
-
-
- -
- - - - - - - - -
-

Registro de Alterações

- -
-
-
-
-
-
-
- - - -
-

Versões Anteriores

- -
-
-
-
-
-
-
- - - - - \ No newline at end of file diff --git a/icon/apple-touch-icon.png b/public/icon/apple-touch-icon.png similarity index 100% rename from icon/apple-touch-icon.png rename to public/icon/apple-touch-icon.png diff --git a/icon/favicon.ico b/public/icon/favicon.ico similarity index 100% rename from icon/favicon.ico rename to public/icon/favicon.ico diff --git a/icon/icon-192-maskable.png b/public/icon/icon-192-maskable.png similarity index 100% rename from icon/icon-192-maskable.png rename to public/icon/icon-192-maskable.png diff --git a/icon/icon-192.png b/public/icon/icon-192.png similarity index 100% rename from icon/icon-192.png rename to public/icon/icon-192.png diff --git a/icon/icon-512-maskable.png b/public/icon/icon-512-maskable.png similarity index 100% rename from icon/icon-512-maskable.png rename to public/icon/icon-512-maskable.png diff --git a/icon/icon-512.png b/public/icon/icon-512.png similarity index 100% rename from icon/icon-512.png rename to public/icon/icon-512.png diff --git a/icon/opentune-black.svg b/public/icon/opentune-black.svg similarity index 100% rename from icon/opentune-black.svg rename to public/icon/opentune-black.svg diff --git a/img/ajustes.webp b/public/img/ajustes.webp similarity index 100% rename from img/ajustes.webp rename to public/img/ajustes.webp diff --git a/img/biblioteca.webp b/public/img/biblioteca.webp similarity index 100% rename from img/biblioteca.webp rename to public/img/biblioteca.webp diff --git a/img/mock.webp b/public/img/mock.webp similarity index 100% rename from img/mock.webp rename to public/img/mock.webp diff --git a/img/reproductor.webp b/public/img/reproductor.webp similarity index 100% rename from img/reproductor.webp rename to public/img/reproductor.webp diff --git a/script.js b/script.js deleted file mode 100644 index a2fe5a2..0000000 --- a/script.js +++ /dev/null @@ -1,1057 +0,0 @@ -/** - * OpenTune App - Main JavaScript - * Versión: 2.0.0 - * Descripción: Script principal para la aplicación web OpenTune - */ - -const APP_CONFIG = { - repositories: { - android: { - repo: 'Arturo254/OpenTune', - currentVersion: '1.9.8', - downloadFormat: '{version}/app-universal-release.apk', - elements: { - version: 'android-version-badge', - download: 'android-download-btn', - text: 'android-download-text', - changelog: 'changelog-dialog', - versions: 'versions-dialog', - changelogContent: 'changelog-content', - versionsList: 'versions-list' - } - }, - windows: { - repo: 'Arturo254/OpenTune-Desktop', - currentVersion: '1.9.0', - downloadFormat: '{version}/OpenTune-Desktop-{version}.exe', - elements: { - version: 'currentVersionWindows', - download: 'downloadBtnWindows', - text: 'downloadTextWindows', - changelog: 'changelogWindows', - versions: 'versionsWindows', - changelogContent: 'changelogContentWindows', - versionsList: 'versionsListWindows' - } - } - }, - urls: { - api: { github: 'https://api.github.com/repos/' }, - demo: 'https://appetize.io/app/b_yb62tcjuqzqjvctnswv3krpnmm' - }, - elements: { - theme: { selector: 'themeSelector', icon: 'themeIcon' }, - language: { selector: 'language-btn', dialog: 'languageDialog', text: 'languageText' }, - warning: { button: 'triggerDialogButton', dialog: 'warningDialog', overlay: 'dialogOverlay', dismiss: 'dismissButton', proceed: 'proceedButton' }, - logo: 'logo' - }, - checkInterval: 60 * 60 * 1000 -}; - -class OpenTuneApp { - constructor(config) { - this.config = config; - this.themeManager = new ThemeManager(config.elements.theme); - this.languageManager = new LanguageManager(config.elements.language); - this.dialogManager = new DialogManager(config.elements.warning, config.urls.demo); - this.logoManager = new LogoManager(config.elements.logo); - this.versionManager = new VersionManager(config.repositories); - this.carouselManager = null; - } - - init() { - this.themeManager.init(); - this.languageManager.init(); - this.dialogManager.init(); - this.logoManager.init(); - this.versionManager.init(); - this.configureMarkdown(); - console.log('OpenTune App inicializada correctamente'); - } - - configureMarkdown() { - if (typeof marked !== 'undefined') { - marked.setOptions({ breaks: true, gfm: true, headerIds: false, sanitize: false }); - } - } -} - -class ThemeManager { - constructor(elements) { - this.selectorId = elements.selector; - this.iconId = elements.icon; - } - - init() { - const selector = document.getElementById(this.selectorId); - const icon = document.getElementById(this.iconId); - if (!selector || !icon) return; - - this.selector = selector; - this.icon = icon; - - // Detectar tema actual basado en las clases del root - const isLightMode = document.documentElement.classList.contains('light-mode'); - this.updateIcon(isLightMode ? 'light' : 'dark'); - - selector.addEventListener('click', () => this.toggleTheme()); - } - - applyTheme(theme) { - const root = document.documentElement; - - if (theme === 'light') { - root.classList.add('light-mode'); - localStorage.setItem('theme', 'light'); - } else { - root.classList.remove('light-mode'); - localStorage.setItem('theme', 'dark'); - } - - this.updateIcon(theme); - - // Disparar evento para que otros componentes se actualicen si es necesario - window.dispatchEvent(new CustomEvent('themeChanged', { detail: { theme } })); - } - - updateIcon(theme) { - if (this.icon) { - this.icon.textContent = theme === 'dark' ? 'light_mode' : 'dark_mode'; - } - } - - toggleTheme() { - const isLightMode = document.documentElement.classList.contains('light-mode'); - this.applyTheme(isLightMode ? 'dark' : 'light'); - } -} - -class LanguageManager { - constructor(elements) { - this.selectorId = elements.selector; - this.dialogId = elements.dialog; - this.textId = elements.text; - } - - init() { - const selector = document.getElementById(this.selectorId); - const dialog = document.getElementById(this.dialogId); - const text = document.getElementById(this.textId); - - if (!selector || !dialog) return; - - // Abrir diálogo al hacer clic en el botón - selector.addEventListener('click', () => { - dialog.showModal(); - }); - - // Cerrar diálogo con el botón X o el botón Cancelar - const closeButtons = dialog.querySelectorAll('[data-close]'); - closeButtons.forEach(btn => { - btn.addEventListener('click', () => { - dialog.close(); - }); - }); - - // Cerrar al hacer clic fuera del diálogo - dialog.addEventListener('click', (e) => { - if (e.target === dialog) { - dialog.close(); - } - }); - - // Configurar funciones globales para cambio de idioma (si existen) - window.closeDialog = () => dialog.close(); - window.setLanguage = (language, url) => { - if (text) text.textContent = language; - dialog.close(); - window.location.href = url; - }; - } -} - -class DialogManager { - constructor(elements, demoUrl) { - this.elements = elements; - this.demoUrl = demoUrl; - } - - init() { - const button = document.getElementById(this.elements.button); - const dialog = document.getElementById(this.elements.dialog); - const overlay = document.getElementById(this.elements.overlay); - const dismissButton = document.getElementById(this.elements.dismiss); - const proceedButton = document.getElementById(this.elements.proceed); - if (!button || !dialog || !overlay) return; - - button.addEventListener('click', () => { - dialog.showModal(); - overlay.style.display = 'block'; - }); - - if (dismissButton) { - dismissButton.addEventListener('click', () => { - dialog.close(); - overlay.style.display = 'none'; - }); - } - - if (proceedButton) { - proceedButton.addEventListener('click', () => { - window.location.href = this.demoUrl; - }); - } - } -} - -class LogoManager { - constructor(element) { - this.elementId = element; - } - - init() { - const logo = document.getElementById(this.elementId); - if (!logo) return; - logo.addEventListener('load', () => this.applyLogoEffects(logo)); - } - - applyLogoEffects(logo) { - try { - const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d'); - const img = new Image(); - img.crossOrigin = 'Anonymous'; - img.src = logo.src; - img.onload = () => { - canvas.width = img.width; - canvas.height = img.height; - ctx.drawImage(img, 0, 0); - try { - const pixels = ctx.getImageData(0, 0, canvas.width, canvas.height).data; - let r = 0, g = 0, b = 0, total = 0; - for (let i = 0; i < pixels.length; i += 4) { r += pixels[i]; g += pixels[i + 1]; b += pixels[i + 2]; total++; } - logo.style.setProperty('--logo-glow-color', `rgb(${Math.floor(r / total)},${Math.floor(g / total)},${Math.floor(b / total)})`); - } catch (e) { - logo.style.setProperty('--logo-glow-color', 'rgba(255,255,255,0.5)'); - } - }; - } catch (e) { - console.error('Error al inicializar efectos del logo:', e); - } - } -} - -class VersionManager { - constructor(repositories) { - this.repositories = repositories; - this.handlers = {}; - } - - init() { - Object.entries(this.repositories).forEach(([platform, config]) => { - if (platform === 'android') this.handlers[platform] = new AndroidVersionHandler(config); - else if (platform === 'windows') this.handlers[platform] = new WindowsVersionHandler(config); - if (this.handlers[platform]) this.handlers[platform].init(); - }); - } -} - -class BaseVersionHandler { - constructor(config) { - this.repo = config.repo; - this.currentVersion = config.currentVersion; - this.latestVersion = config.currentVersion; - this.downloadFormat = config.downloadFormat; - this.elements = config.elements; - } - - async init() { - const versionEl = document.getElementById(this.elements.version); - const downloadBtn = document.getElementById(this.elements.download); - if (!versionEl && !downloadBtn) return; - await this.checkNewVersion(); - setInterval(() => this.checkNewVersion(), APP_CONFIG.checkInterval); - } - - async checkNewVersion() { - const versionEl = document.getElementById(this.elements.version); - const downloadText = document.getElementById(this.elements.text); - try { - const response = await fetch(`${APP_CONFIG.urls.api.github}${this.repo}/releases/latest`); - if (!response.ok) throw new Error(`HTTP ${response.status}`); - const data = await response.json(); - this.latestVersion = data.tag_name; - if (versionEl) versionEl.textContent = data.tag_name; - this.updateDownloadButton(); - return data.tag_name; - } catch (error) { - console.error('Error al verificar versión:', error); - if (versionEl) versionEl.textContent = this.currentVersion; - return null; - } - } - - updateDownloadButton() { - const downloadBtn = document.getElementById(this.elements.download); - const downloadText = document.getElementById(this.elements.text); - if (!downloadBtn) return; - const version = this.latestVersion || this.currentVersion; - const url = `https://github.com/${this.repo}/releases/download/${this.downloadFormat.replace(/\{version\}/g, version)}`; - downloadBtn.href = url; - if (downloadText && this.latestVersion && this.latestVersion !== this.currentVersion) { - downloadText.textContent = `Nueva versión (${this.latestVersion})`; - } - } -} - -class AndroidVersionHandler extends BaseVersionHandler { - constructor(config) { - super(config); - this.initDialogs(); - } - - initDialogs() { - const changelogDialog = document.getElementById(this.elements.changelog); - const versionsDialog = document.getElementById(this.elements.versions); - - if (changelogDialog) { - window.changelog = { - show: () => { changelogDialog.showModal(); this.loadChangelog(); }, - close: () => changelogDialog.close() - }; - } - - if (versionsDialog) { - window.versions = { - show: () => { versionsDialog.showModal(); this.loadVersions(); }, - close: () => versionsDialog.close() - }; - } - } - - async loadChangelog() { - const content = document.getElementById(this.elements.changelogContent); - if (!content) return; - content.innerHTML = '
'; - try { - const response = await fetch(`${APP_CONFIG.urls.api.github}${this.repo}/releases/latest`); - if (!response.ok) throw new Error(`HTTP ${response.status}`); - const data = await response.json(); - if (!data.body) throw new Error('Sin notas de versión'); - const date = new Date(data.published_at).toLocaleDateString('es-ES', { year: 'numeric', month: 'long', day: 'numeric' }); - content.innerHTML = ` -
-

${date}

-
${marked.parse(data.body)}
-
`; - } catch (error) { - content.innerHTML = `

Error: ${error.message}

`; - } - } - - async loadVersions() { - const list = document.getElementById(this.elements.versionsList); - if (!list) return; - list.innerHTML = '
'; - try { - const response = await fetch(`${APP_CONFIG.urls.api.github}${this.repo}/releases`); - if (!response.ok) throw new Error(`HTTP ${response.status}`); - const releases = await response.json(); - list.innerHTML = releases.map((release, i) => { - const type = release.prerelease ? 'beta' : (release.tag_name.toLowerCase().includes('alpha') ? 'alpha' : 'stable'); - const label = type === 'stable' ? 'Estable' : (type === 'beta' ? 'Beta' : 'Alpha'); - const date = new Date(release.published_at).toLocaleDateString('es-ES', { year: 'numeric', month: 'long', day: 'numeric' }); - const downloadUrl = release.assets[0]?.browser_download_url || '#'; - return ` -
-
- ${release.tag_name} - ${i === 0 ? 'Más reciente' : ''} - ${label} - ${date} -
- - download - Descargar - -
`; - }).join(''); - } catch (error) { - list.innerHTML = `

Error: ${error.message}

`; - } - } -} - -class WindowsVersionHandler extends BaseVersionHandler { - constructor(config) { - super(config); - this.initDialogs(); - } - - initDialogs() { - const changelogDialog = document.getElementById(this.elements.changelog); - const versionsDialog = document.getElementById(this.elements.versions); - - if (changelogDialog) { - window.showChangelogWindows = () => { changelogDialog.showModal(); this.loadChangelog(); }; - window.closeChangelogWindows = () => changelogDialog.close(); - } - if (versionsDialog) { - window.showVersionsWindows = () => { versionsDialog.showModal(); this.loadVersions(); }; - window.closeVersionsWindows = () => versionsDialog.close(); - } - } - - async loadChangelog() { - const content = document.getElementById(this.elements.changelogContent); - if (!content) return; - content.innerHTML = '
'; - try { - const response = await fetch(`${APP_CONFIG.urls.api.github}${this.repo}/releases/latest`); - if (!response.ok) throw new Error(`HTTP ${response.status}`); - const data = await response.json(); - content.innerHTML = `
${marked.parse(data.body || 'Sin notas disponibles.')}
`; - } catch (error) { - content.innerHTML = `

Error: ${error.message}

`; - } - } - - async loadVersions() { - const list = document.getElementById(this.elements.versionsList); - if (!list) return; - list.innerHTML = '
'; - try { - const response = await fetch(`${APP_CONFIG.urls.api.github}${this.repo}/releases`); - if (!response.ok) throw new Error(`HTTP ${response.status}`); - const releases = await response.json(); - list.innerHTML = releases.map(release => ` -
-
- ${release.tag_name} - ${new Date(release.published_at).toLocaleDateString()} -
- - download - Descargar - -
`).join(''); - } catch (error) { - list.innerHTML = `

Error: ${error.message}

`; - } - } -} - -class CarouselManager { - constructor() { - this.images = document.querySelectorAll('.carousel-image'); - this.popupOverlay = document.getElementById('popupOverlay'); - this.popupImage = document.getElementById('popupImage'); - this.startX = 0; - } - - init() { - if (!this.images.length || !this.popupOverlay) return; - this.images.forEach(img => { - img.addEventListener('click', e => { - this.popupImage.src = e.target.src; - this.popupOverlay.style.display = 'flex'; - }); - }); - this.popupOverlay.addEventListener('click', e => { - if (e.target === this.popupOverlay) this.popupOverlay.style.display = 'none'; - }); - const closeBtn = document.getElementById('closePopup'); - if (closeBtn) closeBtn.addEventListener('click', () => { this.popupOverlay.style.display = 'none'; }); - this.popupOverlay.addEventListener('touchstart', e => { this.startX = e.touches[0].clientX; }); - this.popupOverlay.addEventListener('touchend', e => { - const diff = this.startX - e.changedTouches[0].clientX; - if (Math.abs(diff) > 50) diff > 0 ? this.nextImage() : this.prevImage(); - }); - } - - nextImage() { - const idx = Array.from(this.images).findIndex(img => img.src === this.popupImage.src); - this.popupImage.src = this.images[(idx + 1) % this.images.length].src; - } - - prevImage() { - const idx = Array.from(this.images).findIndex(img => img.src === this.popupImage.src); - this.popupImage.src = this.images[(idx - 1 + this.images.length) % this.images.length].src; - } -} - -document.addEventListener('DOMContentLoaded', () => { - const app = new OpenTuneApp(APP_CONFIG); - app.init(); - - if (document.querySelectorAll('.carousel-image').length && document.getElementById('popupOverlay')) { - app.carouselManager = new CarouselManager(); - app.carouselManager.init(); - } -}); - - -// Mostrar versión en el badge OSS -(async function updateOssVersion() { - const badge = document.getElementById('oss-version-badge'); - if (!badge) return; - - try { - const response = await fetch('https://api.github.com/repos/Arturo254/OpenTune/releases/latest'); - const data = await response.json(); - badge.textContent = data.tag_name || 'Error'; - } catch (error) { - console.error('Error al cargar versión:', error); - badge.textContent = 'Error'; - } -})(); - - -// ============================================ -// CONFIGURACIÓN DE DIÁLOGOS ANDROID -// ============================================ -document.addEventListener('DOMContentLoaded', function () { - // Elementos de la tarjeta Android - const changelogTrigger = document.getElementById('changelog-trigger'); - const versionsTrigger = document.getElementById('versions-trigger'); - const changelogDialog = document.getElementById('changelog-dialog'); - const versionsDialog = document.getElementById('versions-dialog'); - const closeChangelogBtn = document.getElementById('close-changelog-btn'); - const closeVersionsBtn = document.getElementById('close-versions-btn'); - - // Función para abrir changelog - if (changelogTrigger && changelogDialog) { - changelogTrigger.addEventListener('click', function () { - changelogDialog.showModal(); - // Cargar el changelog automáticamente - loadChangelogContent(); - }); - } - - // Función para abrir versiones - if (versionsTrigger && versionsDialog) { - versionsTrigger.addEventListener('click', function () { - versionsDialog.showModal(); - // Cargar las versiones automáticamente - loadVersionsList(); - }); - } - - // Cerrar diálogos con los botones X - if (closeChangelogBtn && changelogDialog) { - closeChangelogBtn.addEventListener('click', function () { - changelogDialog.close(); - }); - } - - if (closeVersionsBtn && versionsDialog) { - closeVersionsBtn.addEventListener('click', function () { - versionsDialog.close(); - }); - } - - // Cerrar diálogo haciendo clic fuera (opcional) - if (changelogDialog) { - changelogDialog.addEventListener('click', function (e) { - if (e.target === changelogDialog) { - changelogDialog.close(); - } - }); - } - - if (versionsDialog) { - versionsDialog.addEventListener('click', function (e) { - if (e.target === versionsDialog) { - versionsDialog.close(); - } - }); - } -}); - -// Función para cargar el changelog -async function loadChangelogContent() { - const content = document.getElementById('changelog-content'); - if (!content) return; - - content.innerHTML = '
'; - - try { - const response = await fetch('https://api.github.com/repos/Arturo254/OpenTune/releases/latest'); - if (!response.ok) throw new Error(`HTTP ${response.status}`); - - const data = await response.json(); - const date = new Date(data.published_at).toLocaleDateString('es-ES', { - year: 'numeric', - month: 'long', - day: 'numeric' - }); - - // Verificar si marked está disponible - const markdownContent = typeof marked !== 'undefined' ? marked.parse(data.body || 'Sin notas disponibles.') : data.body || 'Sin notas disponibles.'; - - content.innerHTML = ` -
- 📅 ${date} -
-
${markdownContent}
- `; - } catch (error) { - content.innerHTML = `

Error al cargar cambios: ${error.message}

`; - } -} - -// Función para cargar lista de versiones -async function loadVersionsList() { - const list = document.getElementById('versions-list'); - if (!list) return; - - list.innerHTML = '
'; - - try { - const response = await fetch('https://api.github.com/repos/Arturo254/OpenTune/releases'); - if (!response.ok) throw new Error(`HTTP ${response.status}`); - - const releases = await response.json(); - - if (releases.length === 0) { - list.innerHTML = '

No hay versiones disponibles.

'; - return; - } - - list.innerHTML = releases.map((release, index) => { - const date = new Date(release.published_at).toLocaleDateString('es-ES', { - year: 'numeric', - month: 'long', - day: 'numeric' - }); - - const downloadUrl = release.assets[0]?.browser_download_url || '#'; - const isLatest = index === 0; - - return ` -
-
-
- ${release.tag_name} - ${isLatest ? 'Más reciente' : ''} -
- ${date} -
- - download - Descargar - -
- `; - }).join(''); - - } catch (error) { - list.innerHTML = `

Error al cargar versiones: ${error.message}

`; - } -} - -// Diagnóstico del LanguageManager -document.addEventListener('DOMContentLoaded', function () { - const langBtn = document.getElementById('languageSelector'); - const langDialog = document.getElementById('language-dialog'); - - console.log('Botón idioma:', langBtn); - console.log('Diálogo idioma:', langDialog); - - if (langBtn && langDialog) { - // Forzar el evento manualmente - langBtn.addEventListener('click', function (e) { - e.preventDefault(); - console.log('Botón clickeado - abriendo diálogo'); - langDialog.showModal(); - }); - } else { - console.error('No se encontraron los elementos de idioma'); - } -}); - -// ============================================ -// ACCORDION PARA LA SECCIÓN DE SCREENSHOTS -// ============================================ -document.addEventListener('DOMContentLoaded', function () { - const screenshotsContent = document.getElementById('screenshots-content'); - const screenshotsToggle = document.getElementById('screenshots-toggle'); - const screenshotsIcon = document.getElementById('screenshots-icon'); - - if (screenshotsContent && screenshotsToggle) { - - const savedState = localStorage.getItem('screenshotsCollapsed'); - - if (savedState === 'false') { - // Si el usuario lo expandió antes, lo abrimos - screenshotsContent.classList.remove('collapsed'); - if (screenshotsIcon) screenshotsIcon.classList.remove('rotated'); - } - - - screenshotsToggle.addEventListener('click', function () { - screenshotsContent.classList.toggle('collapsed'); - if (screenshotsIcon) screenshotsIcon.classList.toggle('rotated'); - - // Guardar estado - const isCollapsed = screenshotsContent.classList.contains('collapsed'); - localStorage.setItem('screenshotsCollapsed', isCollapsed); - }); - } -}); - -// ============================================ -// OBTENER DATOS REALES DE GITHUB API (VERSIÓN MEJORADA) (Contribuidores.html) -// ============================================ -const REPO_OWNER = 'Arturo254'; -const REPO_NAME = 'OpenTune'; - -async function fetchGitHubStats() { - try { - // Obtener datos del repositorio - const repoResponse = await fetch(`https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}`); - if (!repoResponse.ok) throw new Error('Error al obtener repositorio'); - const repoData = await repoResponse.json(); - - // Stars - document.querySelector('#stats-stars .font-headline-md').textContent = formatNumber(repoData.stargazers_count); - - // Forks - document.querySelector('#stats-forks .font-headline-md').textContent = formatNumber(repoData.forks_count); - - // Issues - document.querySelector('#stats-issues .font-headline-md').textContent = formatNumber(repoData.open_issues_count); - - // Total Commits - usando el endpoint de commits - await fetchTotalCommits(); - - } catch (error) { - console.error('Error:', error); - document.querySelectorAll('.stats-number').forEach(el => el.textContent = 'Error'); - } -} - -async function fetchTotalCommits() { - try { - // Método: obtener la página 1 con per_page=1 y leer el header Link - const response = await fetch(`https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/commits?per_page=1`); - const linkHeader = response.headers.get('Link'); - - let totalCommits = 'N/A'; - if (linkHeader) { - const lastPageMatch = linkHeader.match(/page=(\d+)>; rel="last"/); - if (lastPageMatch) { - totalCommits = formatNumber(parseInt(lastPageMatch[1])); - } - } - - document.querySelector('#stats-commits .font-headline-md').textContent = totalCommits; - } catch (error) { - console.error('Error al obtener commits:', error); - document.querySelector('#stats-commits .font-headline-md').textContent = 'N/A'; - } -} - -function formatNumber(num) { - if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M'; - if (num >= 1000) return (num / 1000).toFixed(1) + 'k'; - return num.toString(); -} - -// Ejecutar -document.addEventListener('DOMContentLoaded', fetchGitHubStats); - -// ============================================ -// OBTENER DATOS REALES DE GITHUB API -// ============================================ - -function formatNumber(num) { - if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M'; - if (num >= 1000) return (num / 1000).toFixed(1) + 'k'; - return num.toString(); -} - -async function fetchGitHubStats() { - try { - const response = await fetch(`https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}`); - if (!response.ok) throw new Error('Error al obtener repositorio'); - const data = await response.json(); - - document.querySelector('#stats-stars .font-headline-md').textContent = formatNumber(data.stargazers_count); - document.querySelector('#stats-forks .font-headline-md').textContent = formatNumber(data.forks_count); - document.querySelector('#stats-issues .font-headline-md').textContent = formatNumber(data.open_issues_count); - - // Total Commits - const commitsResponse = await fetch(`https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/commits?per_page=1`); - const linkHeader = commitsResponse.headers.get('Link'); - let totalCommits = 'N/A'; - if (linkHeader) { - const lastPageMatch = linkHeader.match(/page=(\d+)>; rel="last"/); - if (lastPageMatch) totalCommits = formatNumber(parseInt(lastPageMatch[1])); - } - document.querySelector('#stats-commits .font-headline-md').textContent = totalCommits; - - } catch (error) { - console.error('Error:', error); - } -} - -function getContributorRole(contributions, login) { - if (login === 'Arturo254') return 'Lead Developer'; - if (contributions > 100) return 'Core Contributor'; - if (contributions > 30) return 'Major Contributor'; - if (contributions > 10) return 'Contributor'; - return 'Supporter'; -} - -async function fetchContributors() { - const contributorsGrid = document.getElementById('contributors-grid'); - if (!contributorsGrid) return; - - try { - const response = await fetch(`https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/contributors?per_page=100`); - if (!response.ok) throw new Error('Error al obtener contribuidores'); - const contributors = await response.json(); - - if (contributors.length === 0) return; - - contributorsGrid.innerHTML = contributors.map(contributor => { - const role = getContributorRole(contributor.contributions, contributor.login); - return ` -
- ${contributor.login} -
-
-

${contributor.login}

- ${contributor.contributions} commits -
-
- ${role} -
-
- - open_in_new - -
- `; - }).join(''); - - } catch (error) { - console.error('Error al cargar contribuidores:', error); - } -} - -async function fetchLatestActivity() { - const activityContainer = document.getElementById('latest-activity'); - if (!activityContainer) return; - - try { - const response = await fetch(`https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/commits?per_page=4`); - if (!response.ok) throw new Error('Error al obtener actividad'); - const commits = await response.json(); - - activityContainer.innerHTML = commits.map(commit => ` -
-
-
- commit -
-
-
-

${commit.commit.message.split('\n')[0].substring(0, 60)}

-

by ${commit.author?.login || commit.commit.author.name} • ${new Date(commit.commit.author.date).toLocaleDateString()}

-
-
- `).join(''); - - } catch (error) { - console.error('Error al cargar actividad:', error); - activityContainer.innerHTML = '

Error loading activity

'; - } -} - -document.addEventListener('DOMContentLoaded', () => { - fetchGitHubStats(); - fetchContributors(); - fetchLatestActivity(); -}); - - - -// ============================================ -// FORMULARIO DE CONTACTO - ENVÍO A FORMSPREE -// ============================================ - -// Esperar a que el DOM esté listo -document.addEventListener('DOMContentLoaded', function () { - - // Seleccionar el formulario - const contactForm = document.querySelector('form'); - const submitButton = contactForm?.querySelector('button[type="submit"]'); - - // Crear elemento para mensaje de éxito - const successMessage = document.createElement('div'); - successMessage.id = 'successMessage'; - successMessage.style.cssText = ` - display: none; - text-align: center; - padding: 40px 20px; - background: rgba(208, 188, 255, 0.1); - border-radius: 24px; - border: 1px solid rgba(208, 188, 255, 0.3); - margin-top: 20px; - `; - successMessage.innerHTML = ` - check_circle -

¡Mensaje enviado!

-

Gracias por contactarnos. Te responderemos pronto.

- - `; - - // Insertar mensaje de éxito después del formulario - if (contactForm) { - contactForm.parentNode.appendChild(successMessage); - } - - // Función para mostrar loading - function setLoading(isLoading) { - if (!submitButton) return; - if (isLoading) { - submitButton.disabled = true; - submitButton.style.opacity = '0.7'; - submitButton.style.cursor = 'not-allowed'; - const originalText = submitButton.innerHTML; - submitButton.setAttribute('data-original-text', originalText); - submitButton.innerHTML = 'Enviando...hourglass_empty'; - - // Agregar animación spin si no existe - if (!document.querySelector('#spin-style')) { - const style = document.createElement('style'); - style.id = 'spin-style'; - style.textContent = '@keyframes spin { to { transform: rotate(360deg); } }'; - document.head.appendChild(style); - } - } else { - submitButton.disabled = false; - submitButton.style.opacity = '1'; - submitButton.style.cursor = 'pointer'; - const originalText = submitButton.getAttribute('data-original-text'); - if (originalText) { - submitButton.innerHTML = originalText; - } - } - } - - // Manejar envío del formulario - if (contactForm) { - contactForm.addEventListener('submit', async function (e) { - e.preventDefault(); - - // Obtener valores - const nombreInput = document.querySelector('input[placeholder="Escribe tu nombre aquí"]'); - const emailInput = document.querySelector('input[type="email"]'); - const descripcionTextarea = document.querySelector('textarea'); - const tipoMensajeSelected = document.querySelector('input[name="message_type"]:checked'); - - const nombre = nombreInput?.value || ''; - const email = emailInput?.value || ''; - const descripcion = descripcionTextarea?.value || ''; - const tipo_mensaje = tipoMensajeSelected?.closest('label')?.querySelector('.font-title-md')?.innerText || 'Comentario'; - - // Validar - if (!nombre || !email || !descripcion) { - alert('Por favor, completa todos los campos.'); - return; - } - - if (!email.includes('@')) { - alert('Por favor, ingresa un email válido.'); - return; - } - - // Mostrar loading - setLoading(true); - - try { - const formData = new FormData(); - formData.append('nombre', nombre); - formData.append('email', email); - formData.append('tipo_mensaje', tipo_mensaje); - formData.append('descripcion', descripcion); - - const response = await fetch('https://formspree.io/f/xgvallrq', { - method: 'POST', - body: formData, - headers: { - 'Accept': 'application/json' - } - }); - - if (response.ok) { - // Ocultar formulario, mostrar éxito - contactForm.style.display = 'none'; - successMessage.style.display = 'block'; - } else { - throw new Error('Error en el envío'); - } - } catch (error) { - console.error('Error:', error); - alert('Hubo un error al enviar tu mensaje. Por favor, inténtalo de nuevo.'); - } finally { - setLoading(false); - } - }); - } -}); - - -// ============================================ -// DEMO - DIÁLOGO DE ADVERTENCIA -// ============================================ -document.addEventListener('DOMContentLoaded', function() { - // Elementos - const demoBtn = document.getElementById('hero-demo-btn'); - const warningDialog = document.getElementById('warning-dialog'); - const proceedBtn = document.getElementById('proceedBtn'); - const dismissBtn = document.getElementById('dismissBtn'); - - // Abrir diálogo al hacer clic en "Probar Demo" - if (demoBtn && warningDialog) { - demoBtn.addEventListener('click', function(e) { - e.preventDefault(); - warningDialog.showModal(); - }); - } - - // Ir a la demo al hacer clic en "Continuar" - if (proceedBtn) { - proceedBtn.addEventListener('click', function() { - window.location.href = 'https://appetize.io/app/b_yb62tcjuqzqjvctnswv3krpnmm'; - }); - } - - // Cerrar diálogo al hacer clic en "Cancelar" - if (dismissBtn) { - dismissBtn.addEventListener('click', function() { - warningDialog.close(); - }); - } - - // Cerrar diálogo al hacer clic fuera de él - if (warningDialog) { - warningDialog.addEventListener('click', function(e) { - if (e.target === warningDialog) { - warningDialog.close(); - } - }); - } - - // Cerrar con la tecla ESC (por defecto funciona, pero lo aseguramos) - if (warningDialog) { - warningDialog.addEventListener('cancel', function(e) { - warningDialog.close(); - }); - } -}); \ No newline at end of file diff --git a/src/app/[locale]/contributors/page.tsx b/src/app/[locale]/contributors/page.tsx new file mode 100644 index 0000000..6f7ab0d --- /dev/null +++ b/src/app/[locale]/contributors/page.tsx @@ -0,0 +1,44 @@ +import { setRequestLocale, getTranslations } from 'next-intl/server'; +import { routing } from '@/i18n/routing'; +import { type Locale } from '@config/locales'; +import Navbar from '@cmp/layout/Navbar'; +import Footer from '@cmp/layout/Footer'; +import ContributorsClient from '@cmp/sections/ContributorsClient'; + +export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) { + const { locale } = await params; + const t = await getTranslations({ locale, namespace: 'metadata.contributors' }); + + return { + title: 'Contributors', + description: t('description'), + alternates: { + canonical: `/${locale}/contributors`, + }, + }; +} + +export function generateStaticParams() { + return routing.locales.map((locale) => ({ locale })); +} + +export default async function ContributorsPage({ + params, +}: { + params: Promise<{ locale: string }>; +}) { + const { locale } = await params; + setRequestLocale(locale); + + return ( + <> + +
+ +
+
+
+
+ + ); +} diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx new file mode 100644 index 0000000..b7dfcde --- /dev/null +++ b/src/app/[locale]/layout.tsx @@ -0,0 +1,126 @@ +import { NextIntlClientProvider } from 'next-intl'; +import { getMessages, setRequestLocale, getTranslations } from 'next-intl/server'; +import { notFound } from 'next/navigation'; +import { routing } from '@/i18n/routing'; +import { type Locale } from '@config/locales'; +import Script from 'next/script'; +import { Epilogue, Be_Vietnam_Pro } from 'next/font/google'; +import '@/app/globals.css'; +import { Viewport } from 'next'; +import { DOMAIN, EXTERNAL_LINKS } from '@config/links'; + +const epilogue = Epilogue({ + subsets: ['latin'], + weight: ['400', '500', '600', '700', '800', '900'], + variable: '--font-epilogue-next', +}); + +const beVietnamPro = Be_Vietnam_Pro({ + subsets: ['latin'], + weight: ['400', '500', '600'], + variable: '--font-be-vietnam-pro-next', +}); + +export const viewport: Viewport = { + themeColor: '#d0bcff', +}; + +export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) { + const { locale } = await params; + const t = await getTranslations({ locale, namespace: 'metadata.default' }); + + return { + title: { + template: `%s | OpenTune`, + default: t('title'), + }, + description: t('description'), + metadataBase: new URL(DOMAIN), + alternates: { + canonical: `/${locale}`, + languages: Object.fromEntries(routing.locales.map((lang) => [lang, `/${lang}`])), + }, + robots: { + index: true, + follow: true, + googleBot: { + index: true, + follow: true, + }, + }, + icons: { + icon: [ + { url: '/icon/favicon.ico', sizes: 'any' }, + { url: '/icon/icon-192.png', type: 'image/png', sizes: '192x192' }, + { url: '/icon/icon-512.png', type: 'image/png', sizes: '512x512' }, + ], + apple: [{ url: '/icon/apple-touch-icon.png', sizes: '180x180', type: 'image/png' }], + other: [ + { + rel: 'mask-icon', + url: '/icon/opentune-black.svg', + }, + ], + }, + openGraph: { + type: 'website', + siteName: 'OpenTune', + title: t('title'), + description: t('description'), + images: [ + { + url: '/images/og-image.png', + width: 1200, + height: 630, + alt: 'OpenTune - Material Design 3 YouTube Music Client', + }, + ], + }, + twitter: { + card: 'summary_large_image', + title: t('title'), + description: t('description'), + images: ['/images/og-image.png'], + }, + }; +} + +export function generateStaticParams() { + return routing.locales.map((locale) => ({ locale })); +} + +export default async function LocaleLayout({ + children, + params, +}: { + children: React.ReactNode; + params: Promise<{ locale: string }>; +}) { + const { locale } = await params; + + if (!routing.locales.includes(locale as Locale)) { + notFound(); + } + + setRequestLocale(locale); + + const messages = await getMessages(); + + return ( + + + + {children} + + + + + ); +} diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx new file mode 100644 index 0000000..1ed9259 --- /dev/null +++ b/src/app/[locale]/page.tsx @@ -0,0 +1,61 @@ +import { setRequestLocale, getTranslations } from 'next-intl/server'; +import { routing } from '@/i18n/routing'; +import { type Locale } from '@config/locales'; +import Navbar from '@cmp/layout/Navbar'; +import Footer from '@cmp/layout/Footer'; +import Hero from '@cmp/sections/Hero'; +import Features from '@cmp/sections/Features'; +import OpenSource from '@cmp/sections/OpenSource'; +import Screenshots from '@cmp/sections/Screenshots'; +import SupportCTA from '@cmp/sections/SupportCTA'; +import Downloads from '@cmp/sections/Downloads'; +import { fetchLatestRelease, buildDownloadUrl, REPOS } from '@lib/github'; + +export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) { + const { locale } = await params; + const t = await getTranslations({ locale, namespace: 'metadata.home' }); + + return { + title: t('title'), + description: t('description'), + alternates: { + canonical: `/${locale}`, + }, + }; +} + +export function generateStaticParams() { + return routing.locales.map((locale) => ({ locale })); +} + +export default async function HomePage({ params }: { params: Promise<{ locale: string }> }) { + const { locale } = await params; + setRequestLocale(locale); + + let release; + try { + release = await fetchLatestRelease(REPOS.android); + } catch (error) { + console.error('Failed to fetch latest release:', error); + release = null; + } + const version = release?.tag_name ?? 'latest'; + const downloadUrl = version + ? buildDownloadUrl(REPOS.android, version) + : buildDownloadUrl(REPOS.android, 'latest'); + + return ( + <> + +
+ + + + + + +
+
+ + ); +} diff --git a/src/app/[locale]/support/page.tsx b/src/app/[locale]/support/page.tsx new file mode 100644 index 0000000..2eb503d --- /dev/null +++ b/src/app/[locale]/support/page.tsx @@ -0,0 +1,38 @@ +import { setRequestLocale, getTranslations } from 'next-intl/server'; +import { routing } from '@/i18n/routing'; +import { type Locale } from '@config/locales'; +import Navbar from '@cmp/layout/Navbar'; +import Footer from '@cmp/layout/Footer'; +import SupportClient from '@cmp/sections/SupportClient'; + +export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) { + const { locale } = await params; + const t = await getTranslations({ locale, namespace: 'metadata.support' }); + + return { + title: t('title'), + description: t('description'), + alternates: { + canonical: `/${locale}/support`, + }, + }; +} + +export function generateStaticParams() { + return routing.locales.map((locale) => ({ locale })); +} + +export default async function SupportPage({ params }: { params: Promise<{ locale: string }> }) { + const { locale } = await params; + setRequestLocale(locale); + + return ( + <> + + +
+
+
+ + ); +} diff --git a/src/app/api/github/releases/latest/route.ts b/src/app/api/github/releases/latest/route.ts new file mode 100644 index 0000000..40a204b --- /dev/null +++ b/src/app/api/github/releases/latest/route.ts @@ -0,0 +1,28 @@ +import { NextResponse } from 'next/server'; +import { EXTERNAL_LINKS } from '@config/links'; +import { REPOS, fetchWithTimeout } from '@lib/github'; + +export async function GET() { + const token = process.env.GITHUB_TOKEN; + const headers: HeadersInit = {}; + if (token) { + headers['Authorization'] = `token ${token}`; + } + + try { + const res = await fetchWithTimeout(`${EXTERNAL_LINKS.GITHUB_API}/${REPOS.android}/releases/latest`, { + headers, + next: { revalidate: 3600 }, + timeoutMs: 5000, + }); + + if (!res.ok) { + return NextResponse.json({ error: 'Failed to fetch from GitHub' }, { status: res.status }); + } + + const data = await res.json(); + return NextResponse.json(data); + } catch ($error) { + return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); + } +} diff --git a/src/app/api/github/releases/route.ts b/src/app/api/github/releases/route.ts new file mode 100644 index 0000000..1f5e726 --- /dev/null +++ b/src/app/api/github/releases/route.ts @@ -0,0 +1,33 @@ +import { NextResponse } from 'next/server'; +import { EXTERNAL_LINKS } from '@config/links'; +import { REPOS, fetchWithTimeout } from '@lib/github'; + +export async function GET(request: Request) { + const { searchParams } = new URL(request.url); + const rawPerPage = searchParams.get('per_page'); + const parsedPerPage = parseInt(rawPerPage || '20', 10); + const perPage = isNaN(parsedPerPage) ? 20 : Math.min(Math.max(parsedPerPage, 1), 100); + + const token = process.env.GITHUB_TOKEN; + const headers: HeadersInit = {}; + if (token) { + headers['Authorization'] = `token ${token}`; + } + + try { + const res = await fetchWithTimeout(`${EXTERNAL_LINKS.GITHUB_API}/${REPOS.android}/releases?per_page=${perPage}`, { + headers, + next: { revalidate: 3600 }, + timeoutMs: 5000, + }); + + if (!res.ok) { + return NextResponse.json({ error: 'Failed to fetch from GitHub' }, { status: res.status }); + } + + const data = await res.json(); + return NextResponse.json(data); + } catch ($error) { + return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); + } +} diff --git a/src/app/globals.css b/src/app/globals.css new file mode 100644 index 0000000..228994c --- /dev/null +++ b/src/app/globals.css @@ -0,0 +1,588 @@ +@import 'tailwindcss'; + +/* ─── MD3 Design Tokens ─── */ +@theme { + --color-primary: #e9ddff; + --color-on-primary: #37265e; + --color-primary-container: #d0bcff; + --color-on-primary-container: #594983; + --color-primary-fixed: #e9ddff; + --color-primary-fixed-dim: #d0bcff; + --color-on-primary-fixed: #210f48; + --color-on-primary-fixed-variant: #4d3d76; + --color-inverse-primary: #665590; + + --color-secondary: #ccc2dc; + --color-on-secondary: #332d41; + --color-secondary-container: #4a4359; + --color-on-secondary-container: #bab1ca; + --color-secondary-fixed: #e9def9; + --color-secondary-fixed-dim: #ccc2dc; + --color-on-secondary-fixed: #1e192c; + --color-on-secondary-fixed-variant: #4a4459; + + --color-tertiary: #efb8c8; + --color-on-tertiary: #492532; + --color-tertiary-container: #633b48; + --color-on-tertiary-container: #ffd9e3; + --color-tertiary-fixed: #ffd9e3; + --color-tertiary-fixed-dim: #efb8c8; + --color-on-tertiary-fixed: #31111d; + --color-on-tertiary-fixed-variant: #633b49; + + --color-error: #ffb4ab; + --color-on-error: #690005; + --color-error-container: #93000a; + --color-on-error-container: #ffdad6; + + --color-background: #0e0e11; + --color-on-background: #e5e1e7; + --color-surface: #141317; + --color-on-surface: #e5e1e7; + --color-surface-variant: #49454f; + --color-on-surface-variant: #cac4d0; + --color-outline: #948f9a; + --color-outline-variant: #49454f; + + --font-epilogue: var(--font-epilogue-next); + --font-be-vietnam-pro: var(--font-be-vietnam-pro-next); +} + +@layer base { + html { + scroll-behavior: smooth; + } + body { + background-color: var(--color-background); + color: #e5e1e7; + font-family: var(--font-be-vietnam-pro), sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } +} + +/* ─── Shared Components ─── */ +.glass-card { + background: rgba(43, 41, 45, 0.4); + backdrop-filter: blur(24px); + -webkit-backdrop-filter: blur(24px); + border: 1px solid rgba(255, 255, 255, 0.06); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); + transition: all 0.3s cubic-bezier(0.2, 0, 0, 1); +} + +.feature-icon-wrap { + width: 48px; + height: 48px; + border-radius: 16px; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 20px; +} + +/* ─── Chips ─── */ +.version-chip { + display: inline-flex; + align-items: center; + padding: 4px 12px; + border-radius: 9999px; + background-color: rgba(43, 41, 45, 0.8); + color: #cac4d0; + font-size: 11px; + font-weight: 500; + font-family: var(--font-be-vietnam-pro), sans-serif; + line-height: 16px; +} +.version-chip--stable { + background-color: rgba(239, 184, 200, 0.18); + color: #ffd9e3; +} +.version-chip--beta { + background-color: rgba(74, 67, 89, 0.6); + color: #ccc2dc; +} +.version-chip--alpha { + background-color: rgba(208, 188, 255, 0.15); + color: #e9ddff; +} +.version-chip--latest { + background-color: rgba(208, 188, 255, 0.18); + color: #d0bcff; +} + +/* ─── Footer Chips ─── */ +.footer-chip { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 8px 16px; + border-radius: 9999px; + border: 1px solid rgba(73, 69, 79, 0.5); + color: #948f9a; + font-size: 13px; + font-family: var(--font-be-vietnam-pro), sans-serif; + font-weight: 500; + transition: all 0.2s cubic-bezier(0.2, 0, 0, 1); + text-decoration: none; +} +.footer-chip:hover { + border-color: rgba(208, 188, 255, 0.4); + color: #d0bcff; + background: rgba(208, 188, 255, 0.07); + transform: translateY(-1px); +} + +/* ─── Developer Chip ─── */ +.developer-chip { + animation: shine 3.5s ease-in-out infinite; +} +@keyframes shine { + 0%, + 100% { + opacity: 1; + transform: scale(1); + } + 50% { + opacity: 0.8; + transform: scale(1.04); + } +} + +/* ─── Glass Dialogs ─── */ +.glass-dialog { + position: fixed; + inset: 0; + margin: auto; + width: min(90vw, 480px); + max-height: 85vh; + border-radius: 2rem; + background: rgba(18, 17, 22, 0.88); + backdrop-filter: blur(32px); + -webkit-backdrop-filter: blur(32px); + border: 1px solid rgba(255, 255, 255, 0.08); + color: #e5e1e7; + overflow: hidden; + padding: 0; + box-shadow: + 0 30px 70px rgba(0, 0, 0, 0.55), + 0 0 0 1px rgba(208, 188, 255, 0.06), + inset 0 1px 0 rgba(255, 255, 255, 0.05); +} +.glass-dialog--large { + width: min(90vw, 600px); +} +.glass-dialog::backdrop { + background: rgba(0, 0, 0, 0.72); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); +} +.dialog-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 24px 24px 0; + gap: 12px; +} +.dialog-content { + padding: 20px 24px; +} +.dialog-content--scroll { + overflow-y: auto; + max-height: 58vh; +} +.dialog-content--scroll::-webkit-scrollbar { + width: 4px; +} +.dialog-content--scroll::-webkit-scrollbar-track { + background: transparent; +} +.dialog-content--scroll::-webkit-scrollbar-thumb { + background: rgba(208, 188, 255, 0.25); + border-radius: 2px; +} +.dialog-actions { + display: flex; + justify-content: flex-end; + gap: 8px; + padding: 0 24px 24px; +} + +.dialog-icon-btn { + width: 36px; + height: 36px; + border: none; + border-radius: 9999px; + background: transparent; + color: #cac4d0; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: background 0.2s; + flex-shrink: 0; +} +.dialog-icon-btn:hover { + background: rgba(255, 255, 255, 0.08); +} +.dialog-text-btn { + background: transparent; + border: none; + color: #d0bcff; + font-family: var(--font-be-vietnam-pro), sans-serif; + font-size: 14px; + font-weight: 500; + padding: 10px 20px; + border-radius: 9999px; + cursor: pointer; + transition: background 0.2s; +} +.dialog-text-btn:hover { + background: rgba(208, 188, 255, 0.1); +} +.dialog-filled-btn { + background: #d0bcff; + border: none; + color: #37265e; + font-family: var(--font-be-vietnam-pro), sans-serif; + font-size: 14px; + font-weight: 500; + padding: 10px 24px; + border-radius: 9999px; + cursor: pointer; + transition: all 0.2s; +} +.dialog-filled-btn:hover { + filter: brightness(1.1); +} +.dialog-filled-btn:active { + transform: scale(0.96); +} + +.dialog-list-item { + display: flex; + align-items: center; + gap: 12px; + padding: 12px 16px; + border-radius: 1rem; + color: #e5e1e7; + font-family: var(--font-be-vietnam-pro), sans-serif; + transition: background 0.2s; + cursor: pointer; + text-decoration: none; +} +.dialog-list-item:hover { + background: rgba(255, 255, 255, 0.06); +} +.flag-icon { + width: 24px; + height: 18px; + border-radius: 3px; + object-fit: cover; + flex-shrink: 0; +} + +/* ─── Loading ─── */ +.loading-indicator { + display: flex; + justify-content: center; + align-items: center; + padding: 56px 40px; +} +.circular-progress { + width: 36px; + height: 36px; + border: 3px solid rgba(208, 188, 255, 0.18); + border-top: 3px solid #d0bcff; + border-radius: 50%; + animation: spin 0.85s linear infinite; +} +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +/* ─── Markdown Body ─── */ +.markdown-body h1, +.markdown-body h2, +.markdown-body h3 { + color: #e5e1e7; + font-family: var(--font-epilogue), sans-serif; + margin: 20px 0 10px; +} +.markdown-body h1 { + font-size: 1.4rem; + font-weight: 700; +} +.markdown-body h2 { + font-size: 1.15rem; + font-weight: 600; +} +.markdown-body h3 { + font-size: 1rem; + font-weight: 600; +} +.markdown-body p { + color: #cac4d0; + line-height: 1.75; + margin: 8px 0; +} +.markdown-body ul, +.markdown-body ol { + color: #cac4d0; + padding-left: 22px; + margin: 8px 0; + line-height: 1.75; +} +.markdown-body li { + margin: 4px 0; +} +.markdown-body code { + background: rgba(208, 188, 255, 0.12); + color: #d0bcff; + padding: 2px 8px; + border-radius: 6px; + font-size: 0.82em; + font-family: ui-monospace, 'Courier New', monospace; +} +.markdown-body pre { + background: rgba(14, 14, 17, 0.7); + border: 1px solid rgba(73, 69, 79, 0.4); + border-radius: 12px; + padding: 16px; + overflow-x: auto; + margin: 12px 0; +} +.markdown-body pre code { + background: transparent; + padding: 0; + color: #e5e1e7; +} +.markdown-body a { + color: #d0bcff; + text-decoration: underline; + text-underline-offset: 3px; +} +.markdown-body a:hover { + color: #e9ddff; +} +.markdown-body hr { + border: none; + border-top: 1px solid rgba(73, 69, 79, 0.5); + margin: 20px 0; +} +.changelog-meta { + display: flex; + flex-direction: column; + gap: 8px; + margin-bottom: 20px; + padding-bottom: 16px; + border-bottom: 1px solid rgba(73, 69, 79, 0.4); +} +.changelog-date { + font-size: 13px; + color: #948f9a; + font-family: var(--font-be-vietnam-pro), sans-serif; +} + +/* ─── Version List ─── */ +.version-list-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 14px 0; + gap: 12px; + border-bottom: 1px solid rgba(73, 69, 79, 0.3); +} +.version-list-item:last-child { + border-bottom: none; +} +.version-list-info { + display: flex; + flex-direction: column; + gap: 6px; + flex: 1; + min-width: 0; +} +.version-meta-row { + display: flex; + align-items: center; + gap: 6px; + flex-wrap: wrap; +} +.version-tag { + font-size: 15px; + font-weight: 500; + color: #e5e1e7; + font-family: var(--font-be-vietnam-pro), sans-serif; +} +.version-date { + font-size: 12px; + color: #948f9a; + font-family: var(--font-be-vietnam-pro), sans-serif; +} +.version-dl-btn { + display: inline-flex; + align-items: center; + gap: 6px; + background: rgba(43, 41, 45, 0.8); + color: #e5e1e7; + border: 1px solid rgba(73, 69, 79, 0.4); + padding: 8px 16px; + border-radius: 9999px; + font-size: 13px; + font-weight: 500; + font-family: var(--font-be-vietnam-pro), sans-serif; + text-decoration: none; + transition: all 0.2s; + flex-shrink: 0; + white-space: nowrap; +} +.version-dl-btn:hover { + background: rgba(53, 52, 56, 0.9); + border-color: rgba(208, 188, 255, 0.3); + color: #d0bcff; +} + +/* ─── Disabled Card ─── */ +.disabled-card { + position: relative; + overflow: hidden; + cursor: not-allowed; + user-select: none; +} +.disabled-card::before { + content: ''; + position: absolute; + inset: 0; + background: repeating-linear-gradient( + -45deg, + transparent, + transparent 14px, + rgba(255, 255, 255, 0.018) 14px, + rgba(255, 255, 255, 0.018) 28px + ); + pointer-events: none; + z-index: 0; +} +.disabled-card__inner { + position: relative; + z-index: 1; + opacity: 0.5; + pointer-events: none; +} + +/* ─── Screenshots Accordion ─── */ +#screenshots-content { + max-height: 2000px; + opacity: 1; + overflow: hidden; + transition: + max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), + opacity 0.3s ease, + margin 0.3s ease; +} +#screenshots-content.collapsed { + max-height: 0 !important; + opacity: 0; + margin: 0; + padding: 0; +} +#screenshots-icon { + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} +#screenshots-icon.rotated { + transform: rotate(180deg); +} + +/* ─── Scrollbar ─── */ +::-webkit-scrollbar { + width: 6px; +} +::-webkit-scrollbar-track { + background: transparent; +} +::-webkit-scrollbar-thumb { + background: rgba(208, 188, 255, 0.2); + border-radius: 3px; +} +::-webkit-scrollbar-thumb:hover { + background: rgba(208, 188, 255, 0.38); +} + +/* ─── Focus ─── */ +:focus-visible { + outline: 2px solid #d0bcff; + outline-offset: 2px; + border-radius: 4px; +} + +/* ─── Reduced Motion ─── */ +@media (prefers-reduced-motion: reduce) { + *, + ::before, + ::after { + animation-duration: 0.01ms !important; + transition-duration: 0.01ms !important; + } +} + +/* ─── High Contrast ─── */ +@media (prefers-contrast: high) { + .glass-card { + border-width: 2px; + border-color: rgba(255, 255, 255, 0.25); + } + .glass-dialog { + border-width: 2px; + } +} + +/* ─── Mobile ─── */ +@media (max-width: 640px) { + .glass-dialog { + width: 92vw; + border-radius: 1.5rem; + max-height: 88vh; + } + .dialog-header { + padding: 20px 18px 0; + } + .dialog-content { + padding: 16px 18px; + } + .dialog-actions { + padding: 0 18px 20px; + } +} +@media (max-width: 480px) { + .version-list-item { + flex-direction: column; + align-items: flex-start; + } + .version-dl-btn { + width: 100%; + justify-content: center; + } +} + +/* ─── Skeleton shimmer ─── */ +.skeleton-shimmer { + background: linear-gradient( + 90deg, + rgba(255, 255, 255, 0.05) 0%, + rgba(255, 255, 255, 0.1) 50%, + rgba(255, 255, 255, 0.05) 100% + ); + background-size: 200% 100%; + animation: shimmer 1.5s ease-in-out infinite; +} +@keyframes shimmer { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx new file mode 100644 index 0000000..49578da --- /dev/null +++ b/src/app/layout.tsx @@ -0,0 +1,3 @@ +export default function RootLayout({ children }: { children: React.ReactNode }) { + return children; +} diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx new file mode 100644 index 0000000..3435d05 --- /dev/null +++ b/src/app/not-found.tsx @@ -0,0 +1,63 @@ +import Link from 'next/link'; +import Image from 'next/image'; +import { AlertCircle, Home, ExternalLink } from '@icons'; +import { EXTERNAL_LINKS, PATHS } from '@config/links'; +import '@/app/globals.css'; + +export default function NotFound() { + return ( +
+
+ {/* Text content */} +
+
+ + Error 404 +
+

+ 404 +

+

+ Page not found +

+

+ Whoops! The page you're looking for doesn't exist or has been moved. +

+
+ + + Go to Home + + + + GitHub + +
+
+ + {/* Illustration */} +
+
+
+ 404 illustration +
+
+
+
+ ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx new file mode 100644 index 0000000..677c094 --- /dev/null +++ b/src/app/page.tsx @@ -0,0 +1,6 @@ +import { redirect } from 'next/navigation'; +import { defaultLocale } from '@config/locales'; + +export default function RootPage() { + redirect(`/${defaultLocale}`); +} diff --git a/src/app/robots.ts b/src/app/robots.ts new file mode 100644 index 0000000..67da107 --- /dev/null +++ b/src/app/robots.ts @@ -0,0 +1,12 @@ +import { MetadataRoute } from 'next'; +import { DOMAIN } from '@config/links'; + +export default function robots(): MetadataRoute.Robots { + return { + rules: { + userAgent: '*', + allow: '/', + }, + sitemap: `${DOMAIN}/sitemap.xml`, + }; +} diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts new file mode 100644 index 0000000..88f6a2e --- /dev/null +++ b/src/app/sitemap.ts @@ -0,0 +1,34 @@ +import { MetadataRoute } from 'next'; +import { locales, defaultLocale } from '@config/locales'; +import { DOMAIN, PATHS } from '@config/links'; + +export default function sitemap(): MetadataRoute.Sitemap { + const baseUrl = DOMAIN; + const routes = ['', PATHS.CONTRIBUTORS, PATHS.SUPPORT]; + + const sitemapEntries: MetadataRoute.Sitemap = []; + + for (const route of routes) { + const languages: Record = {}; + locales.forEach((l) => { + languages[l] = `${baseUrl}/${l}${route}`; + }); + languages['x-default'] = `${baseUrl}/${defaultLocale}${route}`; + + for (const locale of locales) { + const url = `${baseUrl}/${locale}${route}`; + + sitemapEntries.push({ + url, + lastModified: new Date(), + changeFrequency: 'weekly', + priority: route === '' ? 1.0 : 0.8, + alternates: { + languages, + }, + }); + } + } + + return sitemapEntries; +} diff --git a/src/app/~test/icon/page.tsx b/src/app/~test/icon/page.tsx new file mode 100644 index 0000000..9d33d4e --- /dev/null +++ b/src/app/~test/icon/page.tsx @@ -0,0 +1,178 @@ +import { Android as Icon, MulOpentune as MulIcon } from '@icons'; + +const name = 'Android'; +const mulName = 'MulOpentune'; + +export default function IconTestPage() { + return ( +
+
+
+
+

+ Icon Test +

+ ~test/icon +
+

+ {name} · {mulName} · Sizing · Colors · Tailwind classes +

+
+ +
+ {/* 1 — size= Prop */} +
+

size= Prop

+
+ {[16, 24, 32, 48, 64].map((s) => ( +
+ + {s}px +
+ ))} +
+
+ + {/* 2 — Tailwind size-* Classes */} +
+

Tailwind size-* Classes

+
+ {(['size-4', 'size-5', 'size-6', 'size-8', 'size-10'] as string[]).map((cls) => ( +
+
+ +
+ {cls} +
+ ))} +
+
+ + {/* 3 — Tailwind Colors via CSS vars */} +
+

Tailwind Colors

+
+ {( + [ + ['var(--color-red-400)', 'red-400'], + ['var(--color-green-400)', 'green-400'], + ['var(--color-blue-400)', 'blue-400'], + ['var(--color-purple-400)', 'purple'], + ['var(--color-amber-400)', 'amber-400'], + ['var(--color-cyan-400)', 'cyan-400'], + ] as [string, string][] + ).map(([token, label]) => ( +
+ + {label} +
+ ))} +
+
+ + {/* 4 — color= Prop */} +
+

color= Prop

+
+ {(['#FF8C00', '#6366F1', '#F72585', '#FF00FF', '#00F5D4', '#84CC16'] as string[]).map( + (hex) => ( +
+ + {hex} +
+ ), + )} +
+
+ + {/* 5 — opacity via CSS */} +
+

CSS opacity

+
+ {( + [ + [1, '100%'], + [0.75, '75%'], + [0.5, '50%'], + [0.25, '25%'], + ] as [number, string][] + ).map(([opacity, label]) => ( +
+
+ + + +
+ {label} +
+ ))} +
+
+ + {/* 6 — Theme Tokens */} +
+

Theme Tokens

+
+ {( + [ + ['var(--color-primary)', 'primary'], + ['var(--color-inverse-primary)', 'inverse'], + ['var(--color-secondary)', 'secndry'], + ['var(--color-tertiary)', 'tertiary'], + ['var(--color-error)', 'error'], + ['var(--color-error-container)', 'errorCont.'], + ] as [string, string][] + ).map(([token, label]) => ( +
+ + {label} +
+ ))} +
+
+
+ + {/* Default vs Mul */} +
+

+ {name} vs {mulName} +

+
+
+ +
+

+ {name} +

+

+ Theme-aware · follows currentColor +

+
+
+ +
+ +
+

+ {mulName} +

+

+ Original artwork +

+
+
+
+
+
+
+ ); +} diff --git a/src/app/~test/layout.tsx b/src/app/~test/layout.tsx new file mode 100644 index 0000000..ad2e175 --- /dev/null +++ b/src/app/~test/layout.tsx @@ -0,0 +1,6 @@ +import '@test/style.css'; +import type { ReactNode } from 'react'; + +export default function TestLayout({ children }: { children: ReactNode }) { + return <>{children}; +} diff --git a/src/app/~test/style.css b/src/app/~test/style.css new file mode 100644 index 0000000..4090351 --- /dev/null +++ b/src/app/~test/style.css @@ -0,0 +1,63 @@ +@import '../globals.css'; +/* ─── Test Environment Styles ─── */ +/* Scoped to ~test routes only. Never import this in globals.css. */ + +.test-page { + min-height: 100vh; + background-color: var(--color-surface-container-lowest); + padding: 2rem 1rem; +} + +.test-section { + background-color: var(--color-surface-container); + border: 1px solid var(--color-outline-variant); + border-radius: var(--radius); + padding: 1.25rem; +} + +.test-section-title { + font-size: 0.75rem; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--color-on-surface-variant); + margin-bottom: 1rem; + font-family: ui-monospace, 'Courier New', monospace; +} + +.test-label { + font-family: ui-monospace, 'Courier New', monospace; + font-size: 0.65rem; + color: var(--color-on-surface-variant); + margin-top: 0.375rem; + text-align: center; + opacity: 0.75; +} + +.test-chip { + display: inline-flex; + align-items: center; + padding: 2px 8px; + border-radius: 9999px; + background-color: color-mix(in srgb, var(--color-primary) 14%, transparent); + color: var(--color-primary); + font-size: 0.65rem; + font-weight: 600; + font-family: ui-monospace, 'Courier New', monospace; + letter-spacing: 0.05em; +} + +.test-hover-zone { + border: 1px dashed var(--color-outline-variant); + border-radius: var(--radius); + padding: 1.5rem; + transition: + border-color 0.2s ease, + background-color 0.2s ease; + cursor: default; +} + +.test-hover-zone:hover { + border-color: var(--color-outline); + background-color: color-mix(in srgb, var(--color-primary) 4%, transparent); +} diff --git a/src/components/dialogs/ChangelogDialog.tsx b/src/components/dialogs/ChangelogDialog.tsx new file mode 100644 index 0000000..249e1b9 --- /dev/null +++ b/src/components/dialogs/ChangelogDialog.tsx @@ -0,0 +1,113 @@ +'use client'; + +import { forwardRef, useCallback, useState } from 'react'; +import { FileText, X } from '@icons'; +import { useTranslations } from 'next-intl'; +import type { GitHubRelease } from '@t/github'; + +interface Props { + locale: string; +} + +const ChangelogDialog = forwardRef(({ locale: $locale }, ref) => { + void $locale; + const t = useTranslations(); + const [content, setContent] = useState(''); + const [loading, setLoading] = useState(false); + const [date, setDate] = useState(''); + + const close = useCallback(() => { + if (ref && 'current' in ref) { + ref.current?.close(); + } + }, [ref]); + + const handleBackdrop = useCallback( + (e: React.MouseEvent) => { + if (ref && 'current' in ref && e.target === ref.current) { + close(); + } + }, + [ref, close], + ); + + const load = useCallback(async () => { + if (content) { + return; + } + setLoading(true); + try { + const res = await fetch("/api/github/releases/latest"); + if (!res.ok) { + throw new Error(`HTTP ${res.status}`); + } + const data = (await res.json()) as GitHubRelease; + const dateStr = new Date(data.published_at).toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric', + }); + setDate(dateStr); + const body = data.body ?? 'No release notes available.'; + const { marked } = await import('marked'); + setContent(await marked.parse(body)); + } catch { + setContent('

Error loading changelog.

'); + } finally { + setLoading(false); + } + }, [content]); + + const open = useCallback(() => { + if (ref && 'current' in ref) { + ref.current?.showModal(); + void load(); + } + }, [ref, load]); + + return ( + <> + + + +
+

+ {t('changelog.title')} +

+ +
+
+ {loading ? ( +
+
+
+ ) : content ? ( +
+ {date && ( +
+ 📅 {date} +
+ )} +
+
+ ) : ( +
+
+
+ )} +
+
+ + ); +}); + +ChangelogDialog.displayName = 'ChangelogDialog'; +export default ChangelogDialog; diff --git a/src/components/dialogs/VersionsDialog.tsx b/src/components/dialogs/VersionsDialog.tsx new file mode 100644 index 0000000..1d6d176 --- /dev/null +++ b/src/components/dialogs/VersionsDialog.tsx @@ -0,0 +1,151 @@ +'use client'; + +import { forwardRef, useCallback, useState } from 'react'; +import { History, X, Download } from '@icons'; +import { useTranslations } from 'next-intl'; +import type { GitHubRelease } from '@t/github'; +import { buildDownloadUrl, REPOS } from '@lib/github'; + +interface Props { + locale: string; +} + +function getReleaseType(release: GitHubRelease): 'stable' | 'beta' | 'alpha' { + if (release.tag_name.toLowerCase().includes('alpha')) { + return 'alpha'; + } + if (release.prerelease) { + return 'beta'; + } + return 'stable'; +} + +const VersionsDialog = forwardRef(({ locale: $locale }, ref) => { + void $locale; + const t = useTranslations(); + const [releases, setReleases] = useState([]); + const [loading, setLoading] = useState(false); + + const close = useCallback(() => { + if (ref && 'current' in ref) { + ref.current?.close(); + } + }, [ref]); + + const handleBackdrop = useCallback( + (e: React.MouseEvent) => { + if (ref && 'current' in ref && e.target === ref.current) { + close(); + } + }, + [ref, close], + ); + + const load = useCallback(async () => { + if (releases.length > 0) { + return; + } + setLoading(true); + try { + const res = await fetch("/api/github/releases?per_page=20"); + if (!res.ok) { + throw new Error(`HTTP ${res.status}`); + } + setReleases((await res.json()) as GitHubRelease[]); + } catch { + setReleases([]); + } finally { + setLoading(false); + } + }, [releases.length]); + + const open = useCallback(() => { + if (ref && 'current' in ref) { + ref.current?.showModal(); + void load(); + } + }, [ref, load]); + + const chipLabel = (type: 'stable' | 'beta' | 'alpha') => { + const map = { stable: t('versions.stable'), beta: 'Beta', alpha: 'Alpha' }; + return map[type]; + }; + + return ( + <> + + + +
+

+ {t('versions.title')} +

+ +
+
+ {loading ? ( +
+
+
+ ) : releases.length > 0 ? ( +
+ {releases.map((release, i) => { + const type = getReleaseType(release); + const dateStr = new Date(release.published_at).toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric', + }); + const url = + release.assets[0]?.browser_download_url ?? + buildDownloadUrl(REPOS.android, release.tag_name); + return ( +
+
+
+ {release.tag_name} + {i === 0 && ( + + {t('versions.latest')} + + )} + + {chipLabel(type)} + +
+ {dateStr} +
+ + + {t('downloads.download')} + +
+ ); + })} +
+ ) : ( +
+
+
+ )} +
+
+ + ); +}); + +VersionsDialog.displayName = 'VersionsDialog'; +export default VersionsDialog; diff --git a/src/components/dialogs/WarningDialog.tsx b/src/components/dialogs/WarningDialog.tsx new file mode 100644 index 0000000..614ed2b --- /dev/null +++ b/src/components/dialogs/WarningDialog.tsx @@ -0,0 +1,56 @@ +'use client'; + +import { useCallback, forwardRef } from 'react'; +import { TriangleAlert } from '@icons'; +import { useTranslations } from 'next-intl'; +import { EXTERNAL_LINKS } from '@config/links'; + +const WarningDialog = forwardRef((_, ref) => { + const t = useTranslations(); + + const close = useCallback(() => { + if (ref && 'current' in ref) { + ref.current?.close(); + } + }, [ref]); + + const proceed = useCallback(() => { + window.location.href = EXTERNAL_LINKS.DEMO; + }, []); + + const handleBackdrop = useCallback( + (e: React.MouseEvent) => { + if (ref && 'current' in ref && e.target === ref.current) { + close(); + } + }, + [ref, close], + ); + + return ( + +
+
+
+ +
+

{t('warning.title')}

+
+
+
+

{t('warning.body')}

+
+
+ + +
+
+ ); +}); + +WarningDialog.displayName = 'WarningDialog'; +export default WarningDialog; diff --git a/src/components/icons/_base.tsx b/src/components/icons/_base.tsx new file mode 100644 index 0000000..f8b5b58 --- /dev/null +++ b/src/components/icons/_base.tsx @@ -0,0 +1,2 @@ +export const DEFAULT_SIZE = 24; +export const COLOR = 'currentColor'; diff --git a/src/components/icons/_index.ts b/src/components/icons/_index.ts new file mode 100644 index 0000000..7f269d2 --- /dev/null +++ b/src/components/icons/_index.ts @@ -0,0 +1,9 @@ +export * from 'lucide-react'; + +export { Opentune, MulOpentune } from '@icon/opentune'; +export { Android } from '@icon/android'; +export { Windows } from '@icon/windows'; +export { YouTubeMusic } from '@icon/youtube-music'; +export { StarPlus } from '@icon/star-plus'; +export { MobileCode } from '@icon/mobile-code'; +export { Crowdsource } from '@icon/crowdsource'; diff --git a/src/components/icons/_template.tsx b/src/components/icons/_template.tsx new file mode 100644 index 0000000..d1ae47b --- /dev/null +++ b/src/components/icons/_template.tsx @@ -0,0 +1,146 @@ +/** + * HOW TO CREATE A CUSTOM ICON + * ============================ + * + * Copy this template and create a new file: + * src/components/icons/.tsx + * cmd: `mv src/components/icons/_template.tsx src/components/icons/.tsx` + * + * There are two variants: + * + * 1. [REQUIRED] Lucide-style — single-color, follows `currentColor`, + * supports size/color/className props — exactly like lucide-react icons. + * Naming: (e.g. Opentune, MyBrand) + * + * 2. [OPTIONAL] Mul (original icon) — has its own hardcoded gradient/colors, + * does not accept a `color` prop (fixed artwork). + * Naming: Mul (e.g. MulOpentune, MulMyBrand) + * Only create this when you also need a separate "branded / full-color" + * version of the icon. + * + * Mul(मूल) means "original" + * + * After exporting, add a line to src/components/icons/_index.ts: + * export { IconName, MulIconName } from '@icon/'; + * (The Mul export is optional) + * ============================ + */ + +import { forwardRef, useId } from 'react'; +import { DEFAULT_SIZE, COLOR } from '@icon/_base'; +import type { IconProps, MulIconProps } from '@icon/_types'; + +// --------------------------------------------------------------------------- +// Put your icon name here (PascalCase) +// --------------------------------------------------------------------------- +const ICON_NAME = 'IconName'; // <-- CHANGE THIS + +// --------------------------------------------------------------------------- +// [REQUIRED] Lucide-style icon +// +// - `size` : controls both width and height (default 24px) +// - `color` : fill color; falls back to `currentColor` when undefined, +// so it can be driven by CSS `color` / Tailwind `text-*` +// - `className` : for Tailwind or CSS classes +// - `...props` : any other SVG attributes (aria-*, role, onClick, etc.) +// - `ref` : forwards an SVGSVGElement ref +// +// Set viewBox to match your SVG, e.g. "0 0 24 24" or "0 0 500 500" +// +// FILL vs STROKE: +// Icons may be fill-based, stroke-based, or a combination of both — +// depending on the original SVG artwork. Do not assume every icon uses +// "fill". Preserve the style of the original SVG: +// - Fill-based : set `fill={color ?? COLOR}` on the (as shown below) +// - Stroke-based: remove the `fill` prop from , set `fill="none"` and +// pass `stroke={color ?? COLOR}` on the inner paths instead +// - Mixed : apply fill/stroke selectively on each child element +// +// ACCESSIBILITY: +// - Decorative icons (purely visual, already labelled by surrounding text) +// should be hidden from assistive technologies: +// +// - Icons that convey meaning on their own, or are interactive, need +// explicit accessibility attributes, for example: +// +// +// All of these props are forwarded automatically via `...props`. +// --------------------------------------------------------------------------- +export const IconName = forwardRef( + ({ size = DEFAULT_SIZE, color, className, ...props }, ref) => ( + + {/* Place your SVG content here — path, circle, rect, etc. */} + + + ), +); +IconName.displayName = ICON_NAME; + +// --------------------------------------------------------------------------- +// [OPTIONAL] Mul (Multicolor) variant +// +// - `size` : sets both width and height at once (default 24px) +// - `width` : overrides only the width (takes priority over size) +// - `height` : overrides only the height (takes priority over size) +// - No `color` prop — colors are hardcoded inside the SVG +// (gradients, multiple fills, etc.) +// - `...props` : any other SVG attributes (including accessibility props) +// +// UNIQUE IDs WITH useId(): +// SVG elements (gradients, clip paths, masks, filters, etc.) require +// an `id` to be referenced elsewhere in the SVG. Static string IDs such as +// "my-gradient" will collide when multiple instances of the same icon are +// rendered on the same page, causing only the first definition to apply. +// Use React's `useId()` to generate a unique ID per instance, then use it +// in both the element and the corresponding reference (e.g. fill="url(#...)"). +// +// If you do not need a multicolor variant, delete this entire block. +// --------------------------------------------------------------------------- +export const MulIconName = forwardRef( + ({ size = DEFAULT_SIZE, width, height, ...props }, ref) => { + const id = useId(); + const gradId = `${id}-grad`; + + return ( + + + + + + + + + {/* Place your multicolor SVG content here */} + + + ); + }, +); +MulIconName.displayName = `Mul${ICON_NAME}`; + +// --------------------------------------------------------------------------- +// Once your icon is done, please delete all the comments in this file — +// including this block, the top doc-comment, and every inline comment above. +// Keep only the imports, the ICON_NAME constant, and the component exports. +// --------------------------------------------------------------------------- diff --git a/src/components/icons/_types.ts b/src/components/icons/_types.ts new file mode 100644 index 0000000..dbea778 --- /dev/null +++ b/src/components/icons/_types.ts @@ -0,0 +1,9 @@ +import type { SVGProps } from 'react'; + +export interface IconProps extends SVGProps { + size?: number | string; +} + +export interface MulIconProps extends Omit, 'color'> { + size?: number | string; +} diff --git a/src/components/icons/android.tsx b/src/components/icons/android.tsx new file mode 100644 index 0000000..b35d382 --- /dev/null +++ b/src/components/icons/android.tsx @@ -0,0 +1,23 @@ +import { forwardRef } from 'react'; +import { DEFAULT_SIZE, COLOR } from '@icon/_base'; +import type { IconProps } from '@icon/_types'; + +const ICON_NAME = 'Android'; + +export const Android = forwardRef( + ({ size = DEFAULT_SIZE, color, className, ...props }, ref) => ( + + + + ), +); +Android.displayName = ICON_NAME; diff --git a/src/components/icons/crowdsource.tsx b/src/components/icons/crowdsource.tsx new file mode 100644 index 0000000..1a90ddc --- /dev/null +++ b/src/components/icons/crowdsource.tsx @@ -0,0 +1,24 @@ +import { forwardRef } from 'react'; +import { DEFAULT_SIZE, COLOR } from '@icon/_base'; +import type { IconProps } from '@icon/_types'; + +const ICON_NAME = 'Crowdsource'; + +export const Crowdsource = forwardRef( + ({ size = DEFAULT_SIZE, color, className, ...props }, ref) => ( + + + + ), +); + +Crowdsource.displayName = ICON_NAME; diff --git a/src/components/icons/mobile-code.tsx b/src/components/icons/mobile-code.tsx new file mode 100644 index 0000000..855988d --- /dev/null +++ b/src/components/icons/mobile-code.tsx @@ -0,0 +1,23 @@ +import { forwardRef } from 'react'; +import { DEFAULT_SIZE, COLOR } from '@icon/_base'; +import type { IconProps } from '@icon/_types'; + +const ICON_NAME = 'MobileCode'; + +export const MobileCode = forwardRef( + ({ size = DEFAULT_SIZE, color, className, ...props }, ref) => ( + + + + ), +); +MobileCode.displayName = ICON_NAME; diff --git a/src/components/icons/opentune.tsx b/src/components/icons/opentune.tsx new file mode 100644 index 0000000..23de97c --- /dev/null +++ b/src/components/icons/opentune.tsx @@ -0,0 +1,80 @@ +import { forwardRef, useId } from 'react'; +import { DEFAULT_SIZE, COLOR } from '@icon/_base'; +import type { IconProps, MulIconProps } from '@icon/_types'; + +export const Opentune = forwardRef( + ({ size = DEFAULT_SIZE, color, className, ...props }, ref) => { + const id = useId(); + const clipId = `${id}-clip`; + + return ( + + + + + + + + + + + ); + }, +); +Opentune.displayName = 'Opentune'; + +export const MulOpentune = forwardRef( + ({ size = DEFAULT_SIZE, width, height, ...props }, ref) => { + const id = useId(); + const gradId = `${id}-grad`; + const clipId = `${id}-clip`; + + return ( + + + + + + + + + + + + + + + ); + }, +); +MulOpentune.displayName = 'MulOpentune'; diff --git a/src/components/icons/star-plus.tsx b/src/components/icons/star-plus.tsx new file mode 100644 index 0000000..9a13792 --- /dev/null +++ b/src/components/icons/star-plus.tsx @@ -0,0 +1,46 @@ +// Remove when StarPlus is released in Lucide. +// Ref: https://github.com/lucide-icons/lucide/pull/3918 +import { forwardRef } from 'react'; +import { DEFAULT_SIZE, COLOR } from '@icon/_base'; +import type { IconProps } from '@icon/_types'; + +const ICON_NAME = 'StarPlus'; + +export const StarPlus = forwardRef( + ({ size = DEFAULT_SIZE, color, className, ...props }, ref) => ( + + + + + + ), +); + +StarPlus.displayName = ICON_NAME; diff --git a/src/components/icons/windows.tsx b/src/components/icons/windows.tsx new file mode 100644 index 0000000..bf5d92d --- /dev/null +++ b/src/components/icons/windows.tsx @@ -0,0 +1,23 @@ +import { forwardRef } from 'react'; +import { DEFAULT_SIZE, COLOR } from '@icon/_base'; +import type { IconProps } from '@icon/_types'; + +const ICON_NAME = 'Windows'; + +export const Windows = forwardRef( + ({ size = DEFAULT_SIZE, color, className, ...props }, ref) => ( + + + + ), +); +Windows.displayName = ICON_NAME; diff --git a/src/components/icons/youtube-music.tsx b/src/components/icons/youtube-music.tsx new file mode 100644 index 0000000..21d268d --- /dev/null +++ b/src/components/icons/youtube-music.tsx @@ -0,0 +1,23 @@ +import { forwardRef } from 'react'; +import { DEFAULT_SIZE, COLOR } from '@icon/_base'; +import type { IconProps } from '@icon/_types'; + +const ICON_NAME = 'YouTubeMusic'; + +export const YouTubeMusic = forwardRef( + ({ size = DEFAULT_SIZE, color, className, ...props }, ref) => ( + + + + ), +); +YouTubeMusic.displayName = ICON_NAME; diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx new file mode 100644 index 0000000..22310c7 --- /dev/null +++ b/src/components/layout/Footer.tsx @@ -0,0 +1,107 @@ +import { useTranslations } from 'next-intl'; +import { MobileCode, Code, Scale, Phone, Crowdsource, LifeBuoy } from '@icons'; +import Link from 'next/link'; +import { type Locale } from '@config/locales'; +import { EXTERNAL_LINKS, PATHS } from '@config/links'; + +export default function Footer({ locale }: { locale: Locale }) { + const t = useTranslations(); + + return ( +
+
+
+
+ OpenTune +

+ {t('footer.copyright')}{' '} + + Arturo.inc™ + + {'. '} + {t('footer.rights')} +

+
+ + +
+ +
+

{t('footer.text')}

+
+ + Arturo254 + + + {t('nav.downloads')} + + + Rajnish + +
+
+
+
+ ); +} diff --git a/src/components/layout/Navbar.tsx b/src/components/layout/Navbar.tsx new file mode 100644 index 0000000..36420b1 --- /dev/null +++ b/src/components/layout/Navbar.tsx @@ -0,0 +1,158 @@ +'use client'; + +import { useTranslations } from 'next-intl'; +import { Link, usePathname } from '@/i18n/routing'; +import Image from 'next/image'; +import { useParams } from 'next/navigation'; +import { type Locale, localeConfig, locales } from '@config/locales'; +import { useCallback, useRef } from 'react'; +import { MulOpentune, X, Globe, ChevronDown, Download } from '@icons'; +import { EXTERNAL_LINKS, PATHS } from '@config/links'; +import { REPOS, buildDownloadUrl } from '@lib/github'; + +export default function Navbar() { + const t = useTranslations(); + const params = useParams(); + const pathname = usePathname(); + const locale = (params['locale'] as Locale) ?? 'en'; + const dialogRef = useRef(null); + + const openLangDialog = useCallback(() => { + dialogRef.current?.showModal(); + }, []); + + const closeLangDialog = useCallback(() => { + dialogRef.current?.close(); + }, []); + + const handleBackdropClick = useCallback( + (e: React.MouseEvent) => { + if (e.target === dialogRef.current) { + closeLangDialog(); + } + }, + [closeLangDialog], + ); + + return ( + <> + {/* Language Dialog */} + +
+

+ {t('lang.select')} +

+ +
+
+
+ {locales.map((loc) => { + const cfg = localeConfig[loc]; + return ( + + {cfg.id.toUpperCase()} + {cfg.displayName} + + ); + })} +
+
+
+ + {/* Nav */} + + + ); +} diff --git a/src/components/sections/ContributorsClient.tsx b/src/components/sections/ContributorsClient.tsx new file mode 100644 index 0000000..2a1a36c --- /dev/null +++ b/src/components/sections/ContributorsClient.tsx @@ -0,0 +1,353 @@ +'use client'; + +import { useTranslations } from 'next-intl'; +import Image from 'next/image'; +import { useEffect, useState } from 'react'; +import { + Heart, + Star, + GitFork, + OctagonAlert, + ArrowRight, + ExternalLink, + Palette, + Languages, + Users, + History, + Bug, + GitCommitHorizontal, + Code, +} from '@icons'; +import MobileBottomNav from '@ui/MobileBottomNav'; +import { type Locale } from '@config/locales'; +import { + formatNumber, + getContributorRole, + REPOS, + fetchContributors, + fetchRecentCommits, + fetchRepo, + fetchTotalCommits, +} from '@lib/github'; +import type { GitHubContributor, GitHubCommit } from '@t/github'; +import { EXTERNAL_LINKS } from '@config/links'; + +interface Stats { + stars: string; + forks: string; + issues: string; + commits: string; +} + +export default function ContributorsClient({ locale }: { locale: Locale }) { + const t = useTranslations(); + + const [stats, setStats] = useState({ stars: '—', forks: '—', issues: '—', commits: '—' }); + const [contributors, setContributors] = useState([]); + const [commits, setCommits] = useState([]); + const [loadingContribs, setLoadingContribs] = useState(true); + const [loadingCommits, setLoadingCommits] = useState(true); + + useEffect(() => { + void (async () => { + try { + const [repo, totalCommits] = await Promise.all([ + fetchRepo(REPOS.android), + fetchTotalCommits(REPOS.android), + ]); + if (repo) { + setStats({ + stars: formatNumber(repo.stargazers_count), + forks: formatNumber(repo.forks_count), + issues: formatNumber(repo.open_issues_count), + commits: totalCommits, + }); + } + } catch { + /* silently fail */ + } + })(); + }, []); + + useEffect(() => { + void (async () => { + try { + const data = await fetchContributors(REPOS.android); + setContributors(data.slice(0, 9)); + } catch { + /* silently fail */ + } finally { + setLoadingContribs(false); + } + })(); + }, []); + + useEffect(() => { + void (async () => { + try { + const data = await fetchRecentCommits(REPOS.android, 4); + setCommits(data); + } catch { + /* silently fail */ + } finally { + setLoadingCommits(false); + } + })(); + }, []); + + const statsData = [ + { id: 'stars', icon: Star, label: t('contributors.stat_stars'), value: stats.stars }, + { id: 'forks', icon: GitFork, label: t('contributors.stat_forks'), value: stats.forks }, + { id: 'issues', icon: OctagonAlert, label: t('contributors.stat_issues'), value: stats.issues }, + { id: 'commits', icon: History, label: t('contributors.stat_commits'), value: stats.commits }, + ]; + + type HelpItem = { + icon: typeof Code; + title: Parameters[0]; + desc: Parameters[0]; + cta: Parameters[0]; + href?: string; + }; + + const helpItems: HelpItem[] = [ + { + icon: Code, + title: 'contributors.help_code_title', + desc: 'contributors.help_code_desc', + cta: 'contributors.help_code_cta', + href: `${EXTERNAL_LINKS.GITHUB_BASE}/${REPOS.android}/issues`, + }, + { + icon: Palette, + title: 'contributors.help_design_title', + desc: 'contributors.help_design_desc', + cta: 'contributors.help_design_cta', + }, + { + icon: Languages, + title: 'contributors.help_translate_title', + desc: 'contributors.help_translate_desc', + cta: 'contributors.help_translate_cta', + }, + { + icon: Bug, + title: 'contributors.help_report_title', + desc: 'contributors.help_report_desc', + cta: 'contributors.help_report_cta', + href: `${EXTERNAL_LINKS.GITHUB_BASE}/${REPOS.android}/issues/new`, + }, + ]; + + return ( +
+
+ {/* Hero */} +
+
+ + {t('contributors.badge')} +
+

+ {t('contributors.title')} +

+

{t('contributors.subtitle')}

+
+ + {/* Stats */} +
+ {statsData.map((s) => ( +
+ + + {s.value} + + {s.label} +
+ ))} +
+ + {/* Contributors Grid */} +
+
+

+ {t('contributors.top_title')} +

+ + {t('contributors.view_all')} + + +
+ +
+ {loadingContribs + ? [1, 2, 3, 4, 5, 6].map((i) => ( +
+
+
+
+
+
+
+
+ )) + : contributors.map((c) => { + const role = getContributorRole(c.contributions, c.login); + return ( +
+
+ {c.login} +
+
+
+
+

+ {c.login} +

+ + {c.contributions} {t('contributors.commits_label')} + +
+
+ + {role} + +
+
+ e.stopPropagation()} + > + + +
+ ); + })} +
+
+ + {/* Bento: How to Help + Activity */} +
+ {/* How to Help */} +
+
+
+

+ {t('contributors.how_title')} +

+

{t('contributors.how_subtitle')}

+
+
+ {helpItems.map((item) => ( +
+
+ + {t(item.title)} +
+

{t(item.desc)}

+ {item.href ? ( + + {t(item.cta)} + + ) : ( + + )} +
+ ))} +
+
+ + {/* Latest Activity */} +
+

+ {t('contributors.activity_title')} +

+
+ {loadingCommits ? ( +
+
+
+ ) : ( + commits.map((commit) => ( +
+
+
+ +
+
+
+

+ {commit.commit.message.split('\n')[0]?.substring(0, 60) ?? ''} +

+

+ by{' '} + + {commit.author?.login ?? commit.commit.author.name} + + {' • '} + {new Date(commit.commit.author.date).toLocaleDateString(locale)} +

+
+
+ )) + )} +
+ + {t('contributors.activity_link')} + +
+
+
+ + +
+ ); +} diff --git a/src/components/sections/Downloads.tsx b/src/components/sections/Downloads.tsx new file mode 100644 index 0000000..f6ffbaa --- /dev/null +++ b/src/components/sections/Downloads.tsx @@ -0,0 +1,122 @@ +'use client'; + +import { useTranslations } from 'next-intl'; +import { useRef } from 'react'; +import { Android, Windows, Download, FileText, History, Ban } from '@icons'; +import ChangelogDialog from '@dialog/ChangelogDialog'; +import VersionsDialog from '@dialog/VersionsDialog'; +import { type Locale } from '@config/locales'; + +interface DownloadsProps { + locale: Locale; + version: string; + downloadUrl: string; +} + +export default function Downloads({ locale, version, downloadUrl }: DownloadsProps) { + const t = useTranslations(); + const changelogRef = useRef(null); + const versionsRef = useRef(null); + + const finalDownloadUrl = + downloadUrl === '#' + ? 'https://github.com/Arturo254/OpenTune/releases/latest/download/app-universal-release.apk' + : downloadUrl; + + return ( +
+
+
+

+ {t('downloads.title')} +

+

{t('downloads.subtitle')}

+
+ +
+ {/* Android Card */} +
+
+
+ +
+
+

Android

+

{t('downloads.android_subtitle')}

+
+
+ +
+ {t('downloads.stable')} + {version || '—'} +
+ +
+ + +
+ +
+ + + {t('downloads.download_apk')} + +

{t('downloads.android_req')}

+
+
+ + {/* Windows Card (Disabled) */} +
+
+
+
+ +
+
+

+ {t('downloads.windows_title')} +

+

{t('downloads.windows_subtitle')}

+
+
+ +
+ {t('downloads.closed')} + {t('downloads.unavailable')} +
+ +
+ + + {t('downloads.changelog')} + + + + {t('downloads.versions')} + +
+ +
+ +
+
+
+
+
+
+ ); +} diff --git a/src/components/sections/Features.tsx b/src/components/sections/Features.tsx new file mode 100644 index 0000000..65fbf81 --- /dev/null +++ b/src/components/sections/Features.tsx @@ -0,0 +1,137 @@ +'use client'; + +import { useTranslations } from 'next-intl'; +import { + YouTubeMusic, + Palette, + Settings, + Search, + Volume2, + ListPlus, + RefreshCw, + Wrench, + Folder, + Languages, + ArrowUpCircle, + Headphones, +} from '@icons'; +import type { IconProps } from '@icon/_types'; + +interface Feature { + icon: React.ComponentType; + titleKey: string; + descKey: string; + color: 'primary' | 'secondary' | 'tertiary'; +} + +const FEATURES: Feature[] = [ + { + icon: YouTubeMusic, + titleKey: 'features.yt_title', + descKey: 'features.yt_desc', + color: 'primary', + }, + { + icon: Palette, + titleKey: 'features.design_title', + descKey: 'features.design_desc', + color: 'secondary', + }, + { icon: Settings, titleKey: 'features.ui_title', descKey: 'features.ui_desc', color: 'tertiary' }, + { + icon: Search, + titleKey: 'features.explore_title', + descKey: 'features.explore_desc', + color: 'primary', + }, + { + icon: Volume2, + titleKey: 'features.quality_title', + descKey: 'features.quality_desc', + color: 'secondary', + }, + { + icon: ListPlus, + titleKey: 'features.playlist_title', + descKey: 'features.playlist_desc', + color: 'tertiary', + }, + { + icon: RefreshCw, + titleKey: 'features.sync_title', + descKey: 'features.sync_desc', + color: 'primary', + }, + { + icon: Wrench, + titleKey: 'features.advanced_title', + descKey: 'features.advanced_desc', + color: 'secondary', + }, + { + icon: Folder, + titleKey: 'features.library_title', + descKey: 'features.library_desc', + color: 'tertiary', + }, + { + icon: Languages, + titleKey: 'features.multilang_title', + descKey: 'features.multilang_desc', + color: 'primary', + }, + { + icon: ArrowUpCircle, + titleKey: 'features.updates_title', + descKey: 'features.updates_desc', + color: 'secondary', + }, + { + icon: Headphones, + titleKey: 'features.ux_title', + descKey: 'features.ux_desc', + color: 'tertiary', + }, +]; + +const colorMap = { + primary: { wrap: 'bg-[#d0bcff]/30 text-[#e9ddff]' }, + secondary: { wrap: 'bg-[#4a4359]/60 text-[#ccc2dc]' }, + tertiary: { wrap: 'bg-[#efb8c8]/30 text-[#ffd9e3]' }, +}; + +export default function Features() { + const t = useTranslations(); + + return ( +
+
+
+

+ {t('features.title')} +

+

{t('features.subtitle')}

+
+ +
+ {FEATURES.map((f) => ( +
+
+ +
+

+ {t(f.titleKey as Parameters[0])} +

+

+ {t(f.descKey as Parameters[0])} +

+
+ ))} +
+
+
+ ); +} diff --git a/src/components/sections/Hero.tsx b/src/components/sections/Hero.tsx new file mode 100644 index 0000000..aa4fea4 --- /dev/null +++ b/src/components/sections/Hero.tsx @@ -0,0 +1,82 @@ +'use client'; + +import { useTranslations } from 'next-intl'; +import Image from 'next/image'; +import Link from 'next/link'; +import { useCallback, useRef } from 'react'; +import { Code, ArrowBigDownDash, CirclePlay } from '@icons'; +import WarningDialog from '@dialog/WarningDialog'; +import { type Locale } from '@config/locales'; +import { PATHS } from '@config/links'; + +export default function Hero({ locale }: { locale: Locale }) { + const t = useTranslations(); + const warningRef = useRef(null); + + const openDemo = useCallback((e: React.MouseEvent) => { + e.preventDefault(); + warningRef.current?.showModal(); + }, []); + + return ( + <> + + +
+ {/* Background glow */} +
+
+
+ +
+ {/* Text */} +
+
+ + {t('hero.badge')} +
+ +

+ OpenTune +

+

+ {t('hero.subtitle')} +

+ +
+ + + {t('hero.download_apk')} + + +
+
+ + {/* Mockup */} +
+
+ OpenTune App Preview +
+
+
+
+
+ + ); +} diff --git a/src/components/sections/OpenSource.tsx b/src/components/sections/OpenSource.tsx new file mode 100644 index 0000000..2b755a6 --- /dev/null +++ b/src/components/sections/OpenSource.tsx @@ -0,0 +1,81 @@ +'use client'; + +import { useTranslations } from 'next-intl'; +import { useEffect, useState } from 'react'; +import Image from 'next/image'; +import { StarPlus, BadgeCheck } from '@icons'; +import { REPOS } from '@lib/github'; +import { EXTERNAL_LINKS } from '@config/links'; + +const GITHUB = 'https://github.com/Arturo254/OpenTune'; + +export default function OpenSource() { + const t = useTranslations(); + const [version, setVersion] = useState(''); + + useEffect(() => { + fetch(`${EXTERNAL_LINKS.GITHUB_API}/${REPOS.android}/releases/latest`) + .then((r) => r.json()) + .then((d: { tag_name?: string }) => setVersion(d.tag_name ?? 'N/A')) + .catch(() => setVersion('N/A')); + }, []); + + return ( +
+
+
+ + {t('oss.badge')} + +

+ {t('oss.title')} +

+

{t('oss.body')}

+
+ + + {t('oss.star')} + +
+ {t('oss.license')} +
+
+
+ +
+
+
+ Arturo254 +
+
+

Arturo254

+

{t('oss.lead')}

+
+
+
+
+ +
+
+

{t('oss.latest_version')}

+

{version || t('oss.loading')}

+
+
+
+
+
+
+ ); +} diff --git a/src/components/sections/Screenshots.tsx b/src/components/sections/Screenshots.tsx new file mode 100644 index 0000000..500294e --- /dev/null +++ b/src/components/sections/Screenshots.tsx @@ -0,0 +1,98 @@ +'use client'; + +import { useTranslations } from 'next-intl'; +import Image from 'next/image'; +import { useCallback, useState } from 'react'; +import { ChevronDown } from '@icons'; + +const SHOTS = [ + { src: '/img/reproductor.webp', labelKey: 'screenshots.player', alt: 'Player Screen' }, + { src: '/img/biblioteca.webp', labelKey: 'screenshots.library', alt: 'Library Screen' }, + { src: '/img/ajustes.webp', labelKey: 'screenshots.settings', alt: 'Settings Screen' }, +]; + +export default function Screenshots() { + const t = useTranslations(); + + const [collapsed, setCollapsed] = useState(() => { + if (typeof window === 'undefined') { + return true; + } + return localStorage.getItem('screenshotsCollapsed') !== 'false'; + }); + + const toggle = useCallback(() => { + setCollapsed((prev) => { + const next = !prev; + localStorage.setItem('screenshotsCollapsed', String(next)); + return next; + }); + }, []); + + return ( +
+
+
+
(e.key === 'Enter' || e.key === ' ') && toggle()} + > +
+

+ {t('screenshots.title')} +

+

{t('screenshots.subtitle')}

+
+ +
+
+ +
+
+ {SHOTS.map((shot, i) => ( +
+
+ {shot.alt} +
+

+ {t(shot.labelKey as Parameters[0])} +

+
+ ))} +
+
+
+
+ ); +} diff --git a/src/components/sections/SupportCTA.tsx b/src/components/sections/SupportCTA.tsx new file mode 100644 index 0000000..63f63c5 --- /dev/null +++ b/src/components/sections/SupportCTA.tsx @@ -0,0 +1,34 @@ +import { useTranslations } from 'next-intl'; +import Link from 'next/link'; +import { Headset, Send } from '@icons'; +import { type Locale } from '@config/locales'; +import { PATHS } from '@config/links'; + +export default function SupportCTA({ locale }: { locale: Locale }) { + const t = useTranslations(); + + return ( +
+
+
+ +
+
+ +
+

+ {t('support.title')} +

+

{t('support.body')}

+ + + {t('support.cta')} + +
+
+
+ ); +} diff --git a/src/components/sections/SupportClient.tsx b/src/components/sections/SupportClient.tsx new file mode 100644 index 0000000..17cc2d0 --- /dev/null +++ b/src/components/sections/SupportClient.tsx @@ -0,0 +1,294 @@ +'use client'; + +import { useTranslations } from 'next-intl'; +import { type Locale } from '@config/locales'; +import { useCallback, useRef, useState } from 'react'; +import { + CheckCircle, + UserRound, + MessageSquareText, + PackagePlus, + ShieldCheck, + Mail, + Loader2, + Send, + Bug, + Clock, + MessageCircle, +} from '@icons'; +import type { IconProps } from '@icon/_types'; +import MobileBottomNav from '@ui/MobileBottomNav'; +import { EXTERNAL_LINKS } from '@config/links'; + +type MessageType = 'comment' | 'request' | 'report'; + +const TYPE_ICONS: Record> = { + comment: MessageSquareText, + request: PackagePlus, + report: Bug, +}; + +const TYPE_COLORS: Record = { + comment: 'text-[#e9ddff] bg-[#e9ddff]/10', + request: 'text-[#ffd9e3] bg-[#ffd9e3]/10', + report: 'text-[#ffb4ab] bg-[#ffb4ab]/10', +}; + +const FORMSPREE_URL = EXTERNAL_LINKS.FORMSPREE; + +export default function SupportClient({ locale }: { locale: Locale }) { + const t = useTranslations(); + + const [messageType, setMessageType] = useState('comment'); + const [loading, setLoading] = useState(false); + const [success, setSuccess] = useState(false); + const [error, setError] = useState(''); + + const nameRef = useRef(null); + const emailRef = useRef(null); + const descRef = useRef(null); + + const handleSubmit = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + const name = nameRef.current?.value.trim() ?? ''; + const email = emailRef.current?.value.trim() ?? ''; + const desc = descRef.current?.value.trim() ?? ''; + + if (!name || !email || !desc) { + setError(t('support_page.validation_all')); + return; + } + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + setError(t('support_page.validation_email')); + return; + } + + setError(''); + setLoading(true); + try { + const form = new FormData(); + form.append('nombre', name); + form.append('email', email); + form.append('tipo_mensaje', messageType); + form.append('descripcion', desc); + + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 10000); + + try { + const res = await fetch(FORMSPREE_URL, { + method: 'POST', + body: form, + headers: { Accept: 'application/json' }, + signal: controller.signal, + }); + + if (res.ok) { + setSuccess(true); + } else { + throw new Error(t('support_page.failed_submit')); + } + } finally { + clearTimeout(timeoutId); + } + } catch { + setError(t('support_page.error_sending')); + } finally { + setLoading(false); + } + }, + [messageType, t], + ); + + const typeKeys: MessageType[] = ['comment', 'request', 'report']; + const typeTitleKeys: Record = { + comment: 'support_page.comment', + request: 'support_page.request', + report: 'support_page.report', + }; + const typeDescKeys: Record = { + comment: 'support_page.comment_desc', + request: 'support_page.request_desc', + report: 'support_page.report_desc', + }; + + return ( +
+
+
+

+ {t('support_page.title')} +

+

{t('support_page.subtitle')}

+
+ +
+
+ + {success ? ( +
+ +

+ {t('support_page.success_title')} +

+

{t('support_page.success_body')}

+ +
+ ) : ( +
{ + void handleSubmit(e); + }} + > +
+ +
+ + +
+
+ +
+ +
+ {typeKeys.map((type) => { + const Icon = TYPE_ICONS[type]; + return ( + + ); + })} +
+
+ +
+ +