- {t("about.content")}
+ {t.about.content}
@@ -186,13 +186,13 @@ export function ContactForm() {
{/* Message */}
@@ -201,7 +201,7 @@ export function ContactForm() {
{/* Product Select */}
diff --git a/components/FAQ.tsx b/components/FAQ.tsx
index 9eac0ff..b0db54b 100644
--- a/components/FAQ.tsx
+++ b/components/FAQ.tsx
@@ -3,7 +3,7 @@
import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { ChevronDown } from "lucide-react";
-import { useTranslations } from "next-intl";
+import { useLanguage } from "@/context/language-context";
interface FaqItem {
questionKey: string;
@@ -15,7 +15,7 @@ interface FaqProps {
}
export function FAQ({ items }: FaqProps) {
- const t = useTranslations();
+ const {t} = useLanguage();
const [openIndex, setOpenIndex] = useState
(0);
const defaultItems: FaqItem[] = [
@@ -60,7 +60,7 @@ export function FAQ({ items }: FaqProps) {
className="text-center mb-16"
>
- {t("faq.title")}
+ {t.faq.title}
@@ -81,7 +81,7 @@ export function FAQ({ items }: FaqProps) {
>
- {t(item.questionKey)}
+ {t.faq.items[idx].question}
- {t(item.answerKey)}
+ {t.faq.items[idx].answer}
diff --git a/components/Footer.tsx b/components/Footer.tsx
index 573e3cc..4d5e92f 100644
--- a/components/Footer.tsx
+++ b/components/Footer.tsx
@@ -1,12 +1,11 @@
"use client";
+import { useLanguage } from "@/context/language-context";
import { motion } from "framer-motion";
-import { useTranslations } from "next-intl";
import { Facebook, Linkedin, Send } from "lucide-react";
export function Footer() {
- const t = useTranslations();
-
+ const {t} = useLanguage();
const socialLinks = [
{ icon: Facebook, href: "#", label: "Facebook" },
{ icon: Linkedin, href: "#", label: "LinkedIn" },
@@ -86,7 +85,7 @@ export function Footer() {
{/* Social */}
- {t("footer.followUs")}
+ {t.footer.followUs}
{socialLinks.map((link) => {
const Icon = link.icon;
@@ -116,7 +115,7 @@ export function Footer() {
viewport={{ once: true }}
className="text-center text-gray-400 text-sm"
>
- {t("footer.copyright")}
+ {t.footer.copyright}
diff --git a/components/Navbar.tsx b/components/Navbar.tsx
index 5db58d3..884c1d3 100644
--- a/components/Navbar.tsx
+++ b/components/Navbar.tsx
@@ -2,10 +2,10 @@
import { useState } from "react";
import Link from "next/link";
-import { usePathname } from "next/navigation";
import { Menu, X } from "lucide-react";
import { motion } from "framer-motion";
-import { useTranslations } from "next-intl";
+import LanguageSwitcher from "./languageSwitcher";
+import { useLanguage } from "@/context/language-context";
interface NavLink {
id: string;
@@ -19,20 +19,15 @@ interface NavbarProps {
export function Navbar({ logoText = "FIRMA" }: NavbarProps) {
const [isOpen, setIsOpen] = useState(false);
- const t = useTranslations();
- const pathname = usePathname();
+ const { t } = useLanguage();
const navLinks: NavLink[] = [
- { id: "about", labelKey: "nav.about", href: "#about" },
- { id: "products", labelKey: "nav.products", href: "#products" },
- { id: "faq", labelKey: "nav.faq", href: "#faq" },
- { id: "contact", labelKey: "nav.contact", href: "#contact" },
+ { id: "about", labelKey: t.nav.about, href: "#about" },
+ { id: "products", labelKey: t.nav.products, href: "#products" },
+ { id: "faq", labelKey: t.nav.faq, href: "#faq" },
+ { id: "contact", labelKey: t.nav.contact , href: "#contact" },
];
- const locale = pathname.split("/")[1];
- const otherLocale = locale === "uz" ? "ru" : "uz";
- const otherPath = pathname.replace(`/${locale}`, `/${otherLocale}`);
-
const handleScroll = (href: string) => {
if (href.startsWith("#")) {
const element = document.querySelector(href);
@@ -50,7 +45,7 @@ export function Navbar({ logoText = "FIRMA" }: NavbarProps) {
{/* Logo */}
{logoText}
@@ -66,21 +61,14 @@ export function Navbar({ logoText = "FIRMA" }: NavbarProps) {
onClick={() => handleScroll(link.href)}
className="text-gray-700 hover:text-blue-600 transition-colors"
>
- {t(link.labelKey)}
+ {link.labelKey}
))}
{/* Language & Mobile Menu */}
-
- {otherLocale.toUpperCase()}
-
+
{/* Mobile Menu Button */}
))}
diff --git a/components/ProductCard.tsx b/components/ProductCard.tsx
index 4fae1d3..cdefc51 100644
--- a/components/ProductCard.tsx
+++ b/components/ProductCard.tsx
@@ -3,8 +3,8 @@
import Image from "next/image";
import { motion } from "framer-motion";
import { ExternalLink } from "lucide-react";
-import { useTranslations } from "next-intl";
import type { Product } from "@/lib/products";
+import { useLanguage } from "@/context/language-context";
interface ProductCardProps {
product: Product;
@@ -12,8 +12,7 @@ interface ProductCardProps {
}
export function ProductCard({ product, onViewDetails }: ProductCardProps) {
- const t = useTranslations();
-
+ const {t} = useLanguage();
return (
@@ -33,10 +32,10 @@ export function ProductCard({ product, onViewDetails }: ProductCardProps) {
{/* Content */}
- {t(product.nameKey)}
+ {product.nameKey}
- {t(product.shortDescriptionKey)}
+ {product.shortDescriptionKey}
{/* Specs Preview */}
@@ -56,7 +55,7 @@ export function ProductCard({ product, onViewDetails }: ProductCardProps) {
onClick={() => onViewDetails(product.slug)}
className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-colors"
>
- {t("products.viewDetails")}
+ Batafsil
diff --git a/components/ProductsGrid.tsx b/components/ProductsGrid.tsx
index f20b2db..c8250f1 100644
--- a/components/ProductsGrid.tsx
+++ b/components/ProductsGrid.tsx
@@ -2,17 +2,17 @@
import { useState } from "react";
import { motion } from "framer-motion";
-import { useTranslations } from "next-intl";
import { ProductCard } from "./ProductCard";
import { getAllProducts } from "@/lib/products";
import type { Product } from "@/lib/products";
import { ProductModal } from "./ProductModal";
import Image from "next/image";
+import { useLanguage } from "@/context/language-context";
// hello everyone
export function ProductsGrid() {
- const t = useTranslations();
+ const {t} = useLanguage();
const products = getAllProducts();
const [selectedProduct, setSelectedProduct] = useState(null);
@@ -58,7 +58,7 @@ export function ProductsGrid() {
className="text-center mb-16 bg-white/80 backdrop-blur-md rounded-xl overflow-hidden p-2 max-w-[300px] w-full mx-auto"
>
- {t("products.title")}
+ {t.products.title}
diff --git a/components/ShowCase.tsx b/components/ShowCase.tsx
index a1ba494..543c52f 100644
--- a/components/ShowCase.tsx
+++ b/components/ShowCase.tsx
@@ -4,24 +4,16 @@ import { useState, useEffect } from "react";
import Image from "next/image";
import { motion, AnimatePresence } from "framer-motion";
import { ChevronLeft, ChevronRight } from "lucide-react";
-import { useTranslations } from "next-intl";
+import { useLanguage } from "@/context/language-context";
//hello again dear
interface ShowCaseProps {
- titleKey: string;
- subtitleKey?: string;
- ctaLabelKey: string;
images: string[];
}
-export function ShowCase({
- titleKey,
- subtitleKey,
- ctaLabelKey,
- images,
-}: ShowCaseProps) {
- const t = useTranslations();
+export function ShowCase({ images }: ShowCaseProps) {
+ const { t } = useLanguage();
const [currentImageIndex, setCurrentImageIndex] = useState(0);
const [autoPlay, setAutoPlay] = useState(true);
@@ -54,7 +46,6 @@ export function ShowCase({
return (
-
{/* background image */}
- {t(titleKey)}
+ {t.hero.title}
-
- {subtitleKey && (
-
- {t(subtitleKey)}
-
- )}
+
+ {t.hero.subtitle}
+
- {t(ctaLabelKey)}
+ {t.hero.cta}
@@ -102,7 +90,7 @@ export function ShowCase({
transition={{ duration: 0.6, delay: 0.2 }}
className="relative"
>
-
+
+
+
+
+
+
+ {languages.map((lang) => (
+ setLanguage(lang.code)}
+ className="cursor-pointer hover:bg-slate-700 text-white"
+ >
+ {lang.name}
+
+ ))}
+
+
+
+ );
+}
diff --git a/components/ui/dropdown-menu.tsx b/components/ui/dropdown-menu.tsx
new file mode 100644
index 0000000..f617c7d
--- /dev/null
+++ b/components/ui/dropdown-menu.tsx
@@ -0,0 +1,257 @@
+'use client'
+
+import * as React from 'react'
+import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
+import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react'
+
+import { cn } from '@/lib/utils'
+
+function DropdownMenu({
+ ...props
+}: React.ComponentProps
) {
+ return
+}
+
+function DropdownMenuPortal({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuTrigger({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuContent({
+ className,
+ sideOffset = 4,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
+
+function DropdownMenuGroup({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuItem({
+ className,
+ inset,
+ variant = 'default',
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean
+ variant?: 'default' | 'destructive'
+}) {
+ return (
+
+ )
+}
+
+function DropdownMenuCheckboxItem({
+ className,
+ children,
+ checked,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
+}
+
+function DropdownMenuRadioGroup({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuRadioItem({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
+}
+
+function DropdownMenuLabel({
+ className,
+ inset,
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
+ return (
+
+ )
+}
+
+function DropdownMenuSeparator({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuShortcut({
+ className,
+ ...props
+}: React.ComponentProps<'span'>) {
+ return (
+
+ )
+}
+
+function DropdownMenuSub({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function DropdownMenuSubTrigger({
+ className,
+ inset,
+ children,
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
+ return (
+
+ {children}
+
+
+ )
+}
+
+function DropdownMenuSubContent({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export {
+ DropdownMenu,
+ DropdownMenuPortal,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuLabel,
+ DropdownMenuItem,
+ DropdownMenuCheckboxItem,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuSeparator,
+ DropdownMenuShortcut,
+ DropdownMenuSub,
+ DropdownMenuSubTrigger,
+ DropdownMenuSubContent,
+}
\ No newline at end of file
diff --git a/context/language-context.tsx b/context/language-context.tsx
new file mode 100644
index 0000000..595556b
--- /dev/null
+++ b/context/language-context.tsx
@@ -0,0 +1,32 @@
+"use client"
+
+import { translations } from "@/lib/translations"
+import { createContext, useContext, useState, type ReactNode } from "react"
+
+type Language = "uz" | "ru"
+
+interface LanguageContextType {
+ language: Language
+ setLanguage: (lang: Language) => void
+ t: (typeof translations)[Language]
+}
+
+const LanguageContext = createContext(undefined)
+
+export function LanguageProvider({ children }: { children: ReactNode }) {
+ const [language, setLanguage] = useState("uz")
+
+ return (
+
+ {children}
+
+ )
+}
+
+export function useLanguage() {
+ const context = useContext(LanguageContext)
+ if (!context) {
+ throw new Error("useLanguage must be used within LanguageProvider")
+ }
+ return context
+}
\ No newline at end of file
diff --git a/i18n.config.ts b/i18n.config.ts
deleted file mode 100644
index 0b067a7..0000000
--- a/i18n.config.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export type Locale = "uz" | "ru";
-
-export const locales: Locale[] = ["uz", "ru"];
-export const defaultLocale: Locale = "uz";
diff --git a/i18n/request.ts b/i18n/request.ts
index b42db61..ae5de74 100644
--- a/i18n/request.ts
+++ b/i18n/request.ts
@@ -1,10 +1,18 @@
-import { getRequestConfig } from "next-intl/server";
+// i18n/request.ts
+import { getRequestConfig, type GetRequestConfigParams } from "next-intl/server";
+import { notFound } from "next/navigation";
-export default getRequestConfig(async ({ requestLocale }) => {
- const locale = (await requestLocale) || "uz";
+export const locales = ['uz','ru'];
+
+export default getRequestConfig(async ({ locale }: GetRequestConfigParams) => {
+ // Agar locale undefined yoki not supported bo‘lsa, 404
+ if (!locale || !locales.includes(locale)) notFound();
+
+ // endi TypeScript uchun locale string ekanligi aniq
+ const messages = (await import(`../locales/${locale}.json`)).default;
return {
- locale,
- messages: (await import(`../locales/${locale}.json`)).default,
+ locale, // string, undefined emas
+ messages, // JSON fayl
};
});
diff --git a/lib/products.ts b/lib/products.ts
index 980ad15..7a529d2 100644
--- a/lib/products.ts
+++ b/lib/products.ts
@@ -13,10 +13,9 @@ export interface Product {
export const products: Product[] = [
{
id: "1",
- nameKey: "products_list.pump_1.name",
- slug: "schotchik-pump",
- shortDescriptionKey: "products_list.pump_1.shortDescription",
- longDescriptionKey: "products_list.pump_1.description",
+ nameKey: "Schotchik Nasos",
+ slug: "Yuqori sifatli schotchik nasos, benzin, dizel va kerosinni tashishda ishlatiladi.",
+ shortDescriptionKey: "Xavfsiz neft mahsulotlarini tashish uchun",
images: ["/images/pump-1.jpg", "/images/pump-1-alt.jpg"],
specs: [
{ key: "Flow Rate", value: "100 L/min" },
@@ -27,10 +26,9 @@ export const products: Product[] = [
},
{
id: "2",
- nameKey: "products_list.pump_2.name",
- slug: "agregat-pump",
- shortDescriptionKey: "products_list.pump_2.shortDescription",
- longDescriptionKey: "products_list.pump_2.description",
+ nameKey: "Agregat Nasos",
+ slug: "Katta volumli neft mahsulotlarini tashishda o'rnatilgan.",
+ shortDescriptionKey: "Kuchli va ishonchli aggregat nasos",
images: ["/images/pump-2.jpg", "/images/pump-2-alt.jpg"],
specs: [
{ key: "Flow Rate", value: "250 L/min" },
@@ -41,10 +39,9 @@ export const products: Product[] = [
},
{
id: "3",
- nameKey: "products_list.pump_3.name",
- slug: "ccl-20-24-pump",
- shortDescriptionKey: "products_list.pump_3.shortDescription",
- longDescriptionKey: "products_list.pump_3.description",
+ nameKey: "СЦЛ 20/24",
+ slug:"Chuqurligi 20-24 metrda ishlaydigan professional nasos.",
+ shortDescriptionKey: "Professional kalibrli nasos",
images: ["/images/pump-3.jpg", "/images/pump-3-alt.jpg"],
specs: [
{ key: "Depth Rating", value: "20-24 m" },
diff --git a/lib/translations.ts b/lib/translations.ts
new file mode 100644
index 0000000..b312e9c
--- /dev/null
+++ b/lib/translations.ts
@@ -0,0 +1,159 @@
+export const translations = {
+ uz: {
+ nav: {
+ about: "Biz haqimizda",
+ products: "Mahsulotlar",
+ faq: "FAQ",
+ contact: "Bog'lanish",
+ },
+ hero: {
+ title: "Sanoat Uskunalari va Nasoslar Yetkazuvchisi",
+ subtitle: "10+ yil tajribasi bilan sifatli mahsulot va xizmat",
+ cta: "Bog'lanish",
+ },
+ about: {
+ title: "Biz haqimizda",
+ content:
+ "Kompaniyamiz sanoat nasoslari va o'lchov uskunalarini yetkazib berishda 10+ yil tajribaga ega. Har bir mahsulot sinovdan o'tkazilgan, sifat kafolatlangan va texnik xizmat ko'rsatish bilan ta'minlanadi. Biz mijozlarimizga texnik maslahat, tez etkazib berish va o'rnatish bo'yicha to'liq xizmat taklif etamiz. Ixtisoslashgan nasoslarimiz (schotchik, agregat nasos, СЦЛ 20/24 va boshqalar) benzin, dizel, kerosin va boshqa yengil neft mahsulotlarini xavfsiz va samarali tashishda ishlatiladi.",
+ },
+ products: {
+ title: "Mahsulotlar",
+ viewDetails: "Batafsil",
+ },
+ faq: {
+ title: "Tez-tez So'raladigan Savollar",
+ items: [
+ {
+ question: "Mahsulotlar uchun kafolat bormi?",
+ answer: "Ha, barcha uskunalarimizga 12 oylik texnik kafolat beriladi.",
+ },
+ {
+ question: "Yetkazib berish muddati qancha?",
+ answer: "Odatda 3-14 ish kuni, mavjudlik va manzilga bog'liq.",
+ },
+ {
+ question: "Texnik qo'llab-quvvatlash bormi?",
+ answer: "Ha, telefon va Telegram orqali 24/7 texnik maslahat mavjud.",
+ },
+ ],
+ },
+ contact: {
+ title: "Bog'lanish",
+ name: "Ism",
+ phone: "Telefon raqami",
+ message: "Xabar",
+ product: "Mahsulot (ixtiyoriy)",
+ send: "Yuborish",
+ success: "Xabar muvaffaqiyatli yuborildi!",
+ error: "Xato: Xabarni yuborib bo'lmadi.",
+ namePlaceholder: "Sizning ismingiz",
+ phonePlaceholder: "+998 XX XXX XX XX",
+ messagePlaceholder: "Sizning xabaringiz (ixtiyoriy)",
+ },
+ footer: {
+ copyright: "© 2025 Firma. Barcha huquqlar himoyalangan.",
+ followUs: "Bizni kuzatib turing",
+ },
+ products_list: {
+ pump_1: {
+ name: "Schotchik Nasos",
+ shortDescription: "Xavfsiz neft mahsulotlarini tashish uchun",
+ description:
+ "Yuqori sifatli schotchik nasos, benzin, dizel va kerosinni tashishda ishlatiladi.",
+ },
+ pump_2: {
+ name: "Agregat Nasos",
+ shortDescription: "Kuchli va ishonchli aggregat nasos",
+ description:
+ "Katta volumli neft mahsulotlarini tashishda o'rnatilgan.",
+ },
+ pump_3: {
+ name: "СЦЛ 20/24",
+ shortDescription: "Professional kalibrli nasos",
+ description:
+ "Chuqurligi 20-24 metrda ishlaydigan professional nasos.",
+ },
+ },
+ },
+
+ ru: {
+ nav: {
+ about: "О нас",
+ products: "Продукты",
+ faq: "FAQ",
+ contact: "Контакт",
+ },
+ hero: {
+ title: "Поставщик промышленного оборудования и насосов",
+ subtitle: "Качественная продукция и услуги с 10+ летним опытом",
+ cta: "Свяжитесь с нами",
+ },
+ about: {
+ title: "О нас",
+ content:
+ "Наша компания имеет 10+ лет опыта в поставке промышленных насосов и измерительного оборудования. Каждый продукт протестирован, качество гарантировано и сопровождается технической поддержкой. Мы предлагаем нашим клиентам полный сервис: техническую консультацию, быструю доставку и установку. Наши специализированные насосы (счетчик, агрегатный насос, СЦЛ 20/24 и др.) используются для безопасной и эффективной транспортировки бензина, дизеля, керосина и других легких нефтепродуктов.",
+ },
+ products: {
+ title: "Продукты",
+ viewDetails: "Подробнее",
+ },
+ faq: {
+ title: "Часто Задаваемые Вопросы",
+ items: [
+ {
+ question: "Гарантия на продукты?",
+ answer:
+ "Да, все наше оборудование поставляется с 12-месячной технической гарантией.",
+ },
+ {
+ question: "Сколько времени займет доставка?",
+ answer:
+ "Обычно 3-14 рабочих дней, в зависимости от наличия и адреса доставки.",
+ },
+ {
+ question: "Есть ли техническая поддержка?",
+ answer:
+ "Да, техническая консультация доступна 24/7 по телефону и Telegram.",
+ },
+ ],
+ },
+ contact: {
+ title: "Свяжитесь с нами",
+ name: "Имя",
+ phone: "Номер телефона",
+ message: "Сообщение",
+ product: "Продукт (опционально)",
+ send: "Отправить",
+ success: "Сообщение успешно отправлено!",
+ error: "Ошибка: не удалось отправить сообщение.",
+ namePlaceholder: "Ваше имя",
+ phonePlaceholder: "+998 XX XXX XX XX",
+ messagePlaceholder: "Ваше сообщение (опционально)",
+ },
+ footer: {
+ copyright: "© 2025 Firma. Все права защищены.",
+ followUs: "Следите за нами",
+ },
+ products_list: {
+ pump_1: {
+ name: "Счетчик Насос",
+ shortDescription:
+ "Для безопасной транспортировки нефтепродуктов",
+ description:
+ "Высококачественный счетчиковый насос, используется для транспортировки бензина, дизеля и керосина.",
+ },
+ pump_2: {
+ name: "Агрегатный Насос",
+ shortDescription: "Мощный и надежный агрегатный насос",
+ description:
+ "Установлен для транспортировки больших объемов нефтепродуктов.",
+ },
+ pump_3: {
+ name: "СЦЛ 20/24",
+ shortDescription: "Профессиональный калиброванный насос",
+ description:
+ "Профессиональный насос, работающий на глубине 20-24 метра.",
+ },
+ },
+ },
+};
diff --git a/middlewere.ts b/middlewere.ts
new file mode 100644
index 0000000..9e864f9
--- /dev/null
+++ b/middlewere.ts
@@ -0,0 +1,10 @@
+import createMiddleware from 'next-intl/middleware';
+
+export default createMiddleware({
+ locales: ['uz', 'ru'],
+ defaultLocale: 'uz'
+});
+
+export const config = {
+ matcher: ['/','/(de|en)/:path*']
+};
diff --git a/next-intl.config.ts b/next-intl.config.ts
new file mode 100644
index 0000000..e0b2675
--- /dev/null
+++ b/next-intl.config.ts
@@ -0,0 +1,8 @@
+// next-intl.config.ts
+import { IntlConfig } from "next-intl";
+
+const nextIntlConfig: IntlConfig = {
+ locale: "uz", // JSON tarjimalar
+};
+
+export default nextIntlConfig;
diff --git a/next.config.ts b/next.config.ts
index 0fb80cb..e9b9bb0 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -1,16 +1,7 @@
-import type { NextConfig } from "next";
-import createNextIntlPlugin from "next-intl/plugin";
+import createNextIntlPlugin from 'next-intl/plugin';
+
+const nextConfig = {};
+
const withNextIntl = createNextIntlPlugin();
-
-const nextConfig: NextConfig = {
- images: {
- remotePatterns: [],
- unoptimized: process.env.NODE_ENV === "development",
- },
- experimental: {
- optimizePackageImports: ["@react-three/fiber", "@react-three/drei"],
- },
-};
-
-export default withNextIntl(nextConfig);
+export default withNextIntl(nextConfig);
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 45aa139..e5bf6f2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,18 +9,22 @@
"version": "0.1.0",
"dependencies": {
"@hookform/resolvers": "^5.2.2",
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
"@react-three/drei": "^10.7.7",
"@react-three/fiber": "^9.4.0",
"axios": "^1.13.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"framer-motion": "^12.23.24",
+ "i18next": "^25.6.3",
"lucide-react": "^0.554.0",
"next": "16.0.4",
- "next-intl": "^4.5.5",
+ "next-i18next": "^15.4.2",
+ "next-intl": "^4.5.6",
"react": "19.2.0",
"react-dom": "19.2.0",
"react-hook-form": "^7.66.1",
+ "react-i18next": "^16.3.5",
"tailwind-merge": "^3.4.0",
"three": "^0.181.2",
"zod": "^4.1.13"
@@ -481,6 +485,44 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@floating-ui/core": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
+ "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/utils": "^0.2.10"
+ }
+ },
+ "node_modules/@floating-ui/dom": {
+ "version": "1.7.4",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz",
+ "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/core": "^1.7.3",
+ "@floating-ui/utils": "^0.2.10"
+ }
+ },
+ "node_modules/@floating-ui/react-dom": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz",
+ "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.7.4"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@floating-ui/utils": {
+ "version": "0.2.10",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
+ "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
+ "license": "MIT"
+ },
"node_modules/@formatjs/ecma402-abstract": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.6.tgz",
@@ -1344,6 +1386,539 @@
"node": ">=12.4.0"
}
},
+ "node_modules/@radix-ui/primitive": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
+ "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
+ "license": "MIT"
+ },
+ "node_modules/@radix-ui/react-arrow": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
+ "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-collection": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
+ "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-context": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
+ "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-direction": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
+ "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
+ "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-escape-keydown": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dropdown-menu": {
+ "version": "2.1.16",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz",
+ "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-menu": "2.1.16",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-guards": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz",
+ "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
+ "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-id": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
+ "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-menu": {
+ "version": "2.1.16",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz",
+ "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.11",
+ "@radix-ui/react-focus-guards": "1.1.3",
+ "@radix-ui/react-focus-scope": "1.1.7",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-popper": "1.2.8",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-roving-focus": "1.1.11",
+ "@radix-ui/react-slot": "1.2.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-popper": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
+ "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/react-dom": "^2.0.0",
+ "@radix-ui/react-arrow": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.1",
+ "@radix-ui/react-use-rect": "1.1.1",
+ "@radix-ui/react-use-size": "1.1.1",
+ "@radix-ui/rect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-portal": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
+ "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-presence": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
+ "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-primitive": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
+ "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.2.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-roving-focus": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz",
+ "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-slot": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
+ "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-callback-ref": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
+ "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-controllable-state": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
+ "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-effect-event": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
+ "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-escape-keydown": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
+ "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-callback-ref": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-rect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
+ "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/rect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-size": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
+ "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/rect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
+ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
+ "license": "MIT"
+ },
"node_modules/@react-three/drei": {
"version": "10.7.7",
"resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-10.7.7.tgz",
@@ -1944,6 +2519,18 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/hoist-non-react-statics": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz",
+ "integrity": "sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==",
+ "license": "MIT",
+ "dependencies": {
+ "hoist-non-react-statics": "^3.3.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*"
+ }
+ },
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
@@ -1987,7 +2574,7 @@
"version": "19.2.3",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"peerDependencies": {
"@types/react": "^19.2.0"
@@ -2655,6 +3242,18 @@
"dev": true,
"license": "Python-2.0"
},
+ "node_modules/aria-hidden": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
+ "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/aria-query": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
@@ -3205,6 +3804,17 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/core-js": {
+ "version": "3.47.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz",
+ "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/core-js"
+ }
+ },
"node_modules/cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
@@ -3399,6 +4009,12 @@
"node": ">=8"
}
},
+ "node_modules/detect-node-es": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
+ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
+ "license": "MIT"
+ },
"node_modules/doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
@@ -4374,6 +4990,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/get-nonce": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
+ "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
@@ -4607,6 +5232,61 @@
"integrity": "sha512-E3a5VwgXimGHwpRGV+WxRTKeSp2DW5DI5MWv34ulL3t5UNmyJWCQ1KmLEHbYzcfThfXG8amBL+fCYPneGHC4VA==",
"license": "Apache-2.0"
},
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "node_modules/html-parse-stringify": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
+ "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
+ "license": "MIT",
+ "dependencies": {
+ "void-elements": "3.1.0"
+ }
+ },
+ "node_modules/i18next": {
+ "version": "25.6.3",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.6.3.tgz",
+ "integrity": "sha512-AEQvoPDljhp67a1+NsnG/Wb1Nh6YoSvtrmeEd24sfGn3uujCtXCF3cXpr7ulhMywKNFF7p3TX1u2j7y+caLOJg==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://locize.com"
+ },
+ {
+ "type": "individual",
+ "url": "https://locize.com/i18next.html"
+ },
+ {
+ "type": "individual",
+ "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4"
+ },
+ "peerDependencies": {
+ "typescript": "^5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/i18next-fs-backend": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.6.1.tgz",
+ "integrity": "sha512-eYWTX7QT7kJ0sZyCPK6x1q+R63zvNKv2D6UdbMf15A8vNb2ZLyw4NNNZxPFwXlIv/U+oUtg8SakW6ZgJZcoqHQ==",
+ "license": "MIT"
+ },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -5868,10 +6548,46 @@
}
}
},
+ "node_modules/next-i18next": {
+ "version": "15.4.2",
+ "resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-15.4.2.tgz",
+ "integrity": "sha512-zgRxWf7kdXtM686ecGIBQL+Bq0+DqAhRlasRZ3vVF0TmrNTWkVhs52n//oU3Fj5O7r/xOKkECDUwfOuXVwTK/g==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://locize.com/i18next.html"
+ },
+ {
+ "type": "individual",
+ "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
+ },
+ {
+ "type": "individual",
+ "url": "https://locize.com"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.23.2",
+ "@types/hoist-non-react-statics": "^3.3.6",
+ "core-js": "^3",
+ "hoist-non-react-statics": "^3.3.2",
+ "i18next-fs-backend": "^2.6.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "i18next": ">= 23.7.13",
+ "next": ">= 12.0.0",
+ "react": ">= 17.0.2",
+ "react-i18next": ">= 13.5.0"
+ }
+ },
"node_modules/next-intl": {
- "version": "4.5.5",
- "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.5.5.tgz",
- "integrity": "sha512-BVAcZP603tZ83c5b/qHaJt5g2/y6YaxQwc8xAlqE9VGf+q5Uc32rpRTlmqCZB8OhcPCO7L6opL47obXJh3uYTw==",
+ "version": "4.5.6",
+ "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.5.6.tgz",
+ "integrity": "sha512-LD1mM9HL44NGqDus3cpIE8wqRU87GWf7rdy1g7UHceT9KJvvjER/jlmIRt3GHaoOiln16K4IbHpO2ZI6jiqiDQ==",
"funding": [
{
"type": "individual",
@@ -5883,9 +6599,9 @@
"@formatjs/intl-localematcher": "^0.5.4",
"@swc/core": "^1.15.2",
"negotiator": "^1.0.0",
- "next-intl-swc-plugin-extractor": "^4.5.5",
- "po-parser": "^0.1.2",
- "use-intl": "^4.5.5"
+ "next-intl-swc-plugin-extractor": "^4.5.6",
+ "po-parser": "^1.0.2",
+ "use-intl": "^4.5.6"
},
"peerDependencies": {
"next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
@@ -5899,9 +6615,9 @@
}
},
"node_modules/next-intl-swc-plugin-extractor": {
- "version": "4.5.5",
- "resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.5.5.tgz",
- "integrity": "sha512-mcq/Eag0SXR1Zcerc4TQxTc4QJdt+5uhLLI7VI1mCbArG/QVsbXcCqd72dKSQpEfz8q0yuTJIlddBs54fT4lkw==",
+ "version": "4.5.6",
+ "resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.5.6.tgz",
+ "integrity": "sha512-ApB3wGYqni8lks90UuaslnCK4a+q8I6ajEafSpknN6RDrs2hUwNuWVrjKhOuhLqNLn4kBKl+Zi5c0WKpL968ag==",
"license": "MIT"
},
"node_modules/next-intl/node_modules/@swc/core": {
@@ -6238,9 +6954,9 @@
}
},
"node_modules/po-parser": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/po-parser/-/po-parser-0.1.3.tgz",
- "integrity": "sha512-VYuhQ4HpLgEvoHryBLSNRx9vI5gcfWKufw7Nv/uMHefQYFferxEtiC9afF7STeOQetIHMYMkrvHxs+H7OERQSw==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/po-parser/-/po-parser-1.0.2.tgz",
+ "integrity": "sha512-yTIQL8PZy7V8c0psPoJUx7fayez+Mo/53MZgX9MPuPHx+Dt+sRPNuRbI+6Oqxnddhkd68x4Nlgon/zizL1Xg+w==",
"license": "MIT"
},
"node_modules/possible-typed-array-names": {
@@ -6394,11 +7110,37 @@
"react": "^16.8.0 || ^17 || ^18 || ^19"
}
},
+ "node_modules/react-i18next": {
+ "version": "16.3.5",
+ "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.3.5.tgz",
+ "integrity": "sha512-F7Kglc+T0aE6W2rO5eCAFBEuWRpNb5IFmXOYEgztjZEuiuSLTe/xBIEG6Q3S0fbl8GXMNo+Q7gF8bpokFNWJww==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.27.6",
+ "html-parse-stringify": "^3.0.1",
+ "use-sync-external-store": "^1.6.0"
+ },
+ "peerDependencies": {
+ "i18next": ">= 25.6.2",
+ "react": ">= 16.8.0",
+ "typescript": "^5"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ },
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/react-reconciler": {
@@ -6422,6 +7164,75 @@
"integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==",
"license": "MIT"
},
+ "node_modules/react-remove-scroll": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz",
+ "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==",
+ "license": "MIT",
+ "dependencies": {
+ "react-remove-scroll-bar": "^2.3.7",
+ "react-style-singleton": "^2.2.3",
+ "tslib": "^2.1.0",
+ "use-callback-ref": "^1.3.3",
+ "use-sidecar": "^1.1.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-remove-scroll-bar": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
+ "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
+ "license": "MIT",
+ "dependencies": {
+ "react-style-singleton": "^2.2.2",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-style-singleton": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
+ "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "get-nonce": "^1.0.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-use-measure": {
"version": "2.1.7",
"resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz",
@@ -7564,10 +8375,31 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/use-callback-ref": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
+ "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/use-intl": {
- "version": "4.5.5",
- "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.5.5.tgz",
- "integrity": "sha512-MUIOVDmZipK23Y2jrVgl/3w15nGcV9nNiz6FNfBFCdgbglOmjB9O7AegZcNFYGXUs5W+vYQYYsQCjmWW/NbhRQ==",
+ "version": "4.5.6",
+ "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.5.6.tgz",
+ "integrity": "sha512-SzxrUH/X3LatVcgWVqz8ifoBK01LC3fzc8Y29Vj0QfrjLIXfGwxvJ3aapyWumBIIHsZmCR0Rx5FpKDWCc9JiOg==",
"license": "MIT",
"dependencies": {
"@formatjs/fast-memoize": "^2.2.0",
@@ -7578,6 +8410,28 @@
"react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0"
}
},
+ "node_modules/use-sidecar": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
+ "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
+ "license": "MIT",
+ "dependencies": {
+ "detect-node-es": "^1.1.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/use-sync-external-store": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
@@ -7596,6 +8450,15 @@
"node": ">= 4"
}
},
+ "node_modules/void-elements": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
+ "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/webgl-constants": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz",
diff --git a/package.json b/package.json
index 2512b2b..b4b8ddb 100644
--- a/package.json
+++ b/package.json
@@ -10,18 +10,22 @@
},
"dependencies": {
"@hookform/resolvers": "^5.2.2",
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
"@react-three/drei": "^10.7.7",
"@react-three/fiber": "^9.4.0",
"axios": "^1.13.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"framer-motion": "^12.23.24",
+ "i18next": "^25.6.3",
"lucide-react": "^0.554.0",
"next": "16.0.4",
- "next-intl": "^4.5.5",
+ "next-i18next": "^15.4.2",
+ "next-intl": "^4.5.6",
"react": "19.2.0",
"react-dom": "19.2.0",
"react-hook-form": "^7.66.1",
+ "react-i18next": "^16.3.5",
"tailwind-merge": "^3.4.0",
"three": "^0.181.2",
"zod": "^4.1.13"
diff --git a/public/product/product1.jpg b/public/product/product1.jpg
new file mode 100644
index 0000000..50bd18c
Binary files /dev/null and b/public/product/product1.jpg differ
diff --git a/public/product/product2.jpg b/public/product/product2.jpg
new file mode 100644
index 0000000..1a0a60d
Binary files /dev/null and b/public/product/product2.jpg differ
diff --git a/public/product/product3.jpg b/public/product/product3.jpg
new file mode 100644
index 0000000..6790683
Binary files /dev/null and b/public/product/product3.jpg differ
diff --git a/tsconfig.json b/tsconfig.json
index 3a13f90..39da4b3 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -29,6 +29,6 @@
".next/types/**/*.ts",
".next/dev/types/**/*.ts",
"**/*.mts"
- ],
- "exclude": ["node_modules"]
+, "next.config.ts" ],
+ "exclude": ["node_modules",".next"]
}