Compare commits
10 Commits
e87a26d74c
...
49f5c0979a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49f5c0979a | ||
|
|
671344669c | ||
|
|
b9792e7eb5 | ||
|
|
638e5518e4 | ||
|
|
ce8d14c9b2 | ||
|
|
29e06be337 | ||
|
|
196f99d8dd | ||
|
|
ac7cd51600 | ||
|
|
21cb013cd8 | ||
|
|
de2554a2e7 |
25
app/[locale]/home/page.tsx
Normal file
25
app/[locale]/home/page.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import {
|
||||
AboutUs,
|
||||
Banner,
|
||||
Blog,
|
||||
Line,
|
||||
OurService,
|
||||
Statistics,
|
||||
Testimonial,
|
||||
Video,
|
||||
} from "@/components/pages/home";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="bg-slate-950">
|
||||
<Banner />
|
||||
<Statistics />
|
||||
<AboutUs />
|
||||
<Line />
|
||||
<Blog />
|
||||
<Video />
|
||||
<OurService />
|
||||
{/* <Testimonial /> */}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
6
app/[locale]/page.tsx
Normal file
6
app/[locale]/page.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
import { redirect } from 'next/navigation'
|
||||
import React from 'react'
|
||||
|
||||
export default function Page() {
|
||||
return redirect('/home')
|
||||
}
|
||||
143
app/globals.css
143
app/globals.css
@@ -1,9 +1,60 @@
|
||||
@import 'tailwindcss';
|
||||
@import 'tw-animate-css';
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
@layer {
|
||||
@import url("https://fonts.googleapis.com/css2?family=Almarai:wght@300;400;700&display=swap");
|
||||
@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100..900;1,100..900&display=swap");
|
||||
@import url("https://fonts.googleapis.com/css2?family=Unbounded:wght@200..900&display=swap");
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
--font-roboto: "Roboto", sans-serif;
|
||||
--font-almarai: "Almarai", sans-serif;
|
||||
--font-unbounded:"Unbounded",sans-serif;
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-ring: var(--ring);
|
||||
--color-input: var(--input);
|
||||
--color-border: var(--border);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-card: var(--card);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--radius-2xl: calc(var(--radius) + 8px);
|
||||
--radius-3xl: calc(var(--radius) + 12px);
|
||||
--radius-4xl: calc(var(--radius) + 16px);
|
||||
}
|
||||
|
||||
:root {
|
||||
--radius: 0.625rem;
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
@@ -19,7 +70,6 @@
|
||||
--accent: oklch(0.97 0 0);
|
||||
--accent-foreground: oklch(0.205 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--destructive-foreground: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.922 0 0);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
@@ -28,7 +78,6 @@
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--radius: 0.625rem;
|
||||
--sidebar: oklch(0.985 0 0);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
@@ -42,11 +91,11 @@
|
||||
.dark {
|
||||
--background: oklch(0.145 0 0);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.145 0 0);
|
||||
--card: oklch(0.205 0 0);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.145 0 0);
|
||||
--popover: oklch(0.205 0 0);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.985 0 0);
|
||||
--primary: oklch(0.922 0 0);
|
||||
--primary-foreground: oklch(0.205 0 0);
|
||||
--secondary: oklch(0.269 0 0);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
@@ -54,11 +103,10 @@
|
||||
--muted-foreground: oklch(0.708 0 0);
|
||||
--accent: oklch(0.269 0 0);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.396 0.141 25.723);
|
||||
--destructive-foreground: oklch(0.637 0.237 25.331);
|
||||
--border: oklch(0.269 0 0);
|
||||
--input: oklch(0.269 0 0);
|
||||
--ring: oklch(0.439 0 0);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.556 0 0);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
@@ -70,49 +118,8 @@
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.269 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||
--sidebar-border: oklch(0.269 0 0);
|
||||
--sidebar-ring: oklch(0.439 0 0);
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--font-sans: 'Geist', 'Geist Fallback';
|
||||
--font-mono: 'Geist Mono', 'Geist Mono Fallback';
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.556 0 0);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
@@ -124,26 +131,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.loi{
|
||||
color:#a6040400;
|
||||
body {
|
||||
background: #1e1d1c;
|
||||
}
|
||||
|
||||
.gradient-text {
|
||||
background: linear-gradient(
|
||||
to bottom right,
|
||||
#ffffff 0%,
|
||||
#ffffff 50%,
|
||||
rgba(255, 255, 255, 0.5) 100%
|
||||
);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
text gradient tailwindd classlari
|
||||
|
||||
bg-linear-to-br from-white via-white to-white/50
|
||||
text-transparent bg-clip-text
|
||||
*/
|
||||
@@ -4,9 +4,18 @@ import { Geist, Geist_Mono } from "next/font/google";
|
||||
import { Analytics } from "@vercel/analytics/next";
|
||||
import "./globals.css";
|
||||
import { Footer, Navbar } from "@/components/layout";
|
||||
import { NextIntlClientProvider } from "next-intl";
|
||||
import { getMessages } from "next-intl/server";
|
||||
|
||||
const _geist = Geist({ subsets: ["latin"] });
|
||||
const _geistMono = Geist_Mono({ subsets: ["latin"] });
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "FireForce - Emergency Services",
|
||||
@@ -32,18 +41,26 @@ export const metadata: Metadata = {
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
params,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
params: any;
|
||||
}>) {
|
||||
const { locale } = await params;
|
||||
const messages: any = await getMessages();
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={`font-sans antialiased`}>
|
||||
<Navbar />
|
||||
{children}
|
||||
<Footer />
|
||||
<Analytics />
|
||||
<html lang={locale} suppressHydrationWarning>
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
<NextIntlClientProvider messages={messages} locale={locale}>
|
||||
<Navbar />
|
||||
{children}
|
||||
<Footer />
|
||||
<Analytics />
|
||||
</NextIntlClientProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
24
app/page.tsx
24
app/page.tsx
@@ -1,25 +1,5 @@
|
||||
import {
|
||||
AboutUs,
|
||||
Banner,
|
||||
Blog,
|
||||
Line,
|
||||
OurService,
|
||||
Statistics,
|
||||
Testimonial,
|
||||
Video,
|
||||
} from "@/components/pages/home";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="bg-slate-950">
|
||||
<Banner />
|
||||
<Statistics />
|
||||
<AboutUs />
|
||||
<Video />
|
||||
<OurService />
|
||||
<Testimonial />
|
||||
<Line />
|
||||
<Blog />
|
||||
</main>
|
||||
);
|
||||
return redirect('/uz/home')
|
||||
}
|
||||
|
||||
23
components/Counter.tsx
Normal file
23
components/Counter.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
"use client";
|
||||
import { useEffect, useState } from "react";
|
||||
import { animate, motion, useMotionValue, useTransform } from "framer-motion";
|
||||
|
||||
export function Counter({ countNum }: { countNum: number }) {
|
||||
const count = useMotionValue(0);
|
||||
const rounded = useTransform(count, (latest:any) => Math.round(latest));
|
||||
const [displayValue, setDisplayValue] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const controls = animate(count, countNum, {
|
||||
duration: 2,
|
||||
ease: "easeOut",
|
||||
onUpdate: (latest:any) => {
|
||||
setDisplayValue(Math.round(latest));
|
||||
},
|
||||
});
|
||||
|
||||
return () => controls.stop();
|
||||
}, [countNum]); // countNum dependency qo'shildi
|
||||
|
||||
return <motion.span>{displayValue}</motion.span>;
|
||||
}
|
||||
120
components/languageSwitcher.tsx
Normal file
120
components/languageSwitcher.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useTransition } from "react";
|
||||
import { useRouter, usePathname } from "next/navigation";
|
||||
import { Check, ChevronDown, Globe } from "lucide-react";
|
||||
import { locales, localeFlags, localeNames, type Locale } from "@/i18n/config";
|
||||
import { useLocale } from "next-intl";
|
||||
|
||||
export default function LanguageSelectRadix() {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const currentLocale = useLocale() as Locale;
|
||||
const [isPending, startTransition] = useTransition();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const changeLanguage = (newLocale: Locale) => {
|
||||
if (newLocale === currentLocale) {
|
||||
setIsOpen(false);
|
||||
return;
|
||||
}
|
||||
|
||||
startTransition(() => {
|
||||
// ✅ 1. Set cookie (middleware will sync this)
|
||||
document.cookie = `NEXT_LOCALE=${newLocale}; path=/; max-age=31536000; SameSite=Lax`;
|
||||
|
||||
// ✅ 2. Build new path
|
||||
const segments = pathname.split("/").filter(Boolean);
|
||||
|
||||
// Remove current locale if exists
|
||||
const pathWithoutLocale =
|
||||
segments[0] && locales.includes(segments[0] as Locale)
|
||||
? segments.slice(1)
|
||||
: segments;
|
||||
|
||||
// Add new locale
|
||||
const newPath = `/${newLocale}${
|
||||
pathWithoutLocale.length ? "/" + pathWithoutLocale.join("/") : ""
|
||||
}`;
|
||||
|
||||
// ✅ 3. Navigate (middleware will handle the rest)
|
||||
router.push(newPath);
|
||||
|
||||
// ✅ 4. Force refresh after navigation completes
|
||||
setTimeout(() => {
|
||||
router.refresh();
|
||||
}, 100); // Small delay ensures navigation completes
|
||||
});
|
||||
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
{/* Trigger Button */}
|
||||
<button
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
disabled={isPending}
|
||||
className="inline-flex items-center justify-between gap-2 px-2 py-1 border border-gray-300 hover:border-red-600
|
||||
rounded-lg text-white text-sm font-medium shadow-sm hover:bg-red-600 disabled:opacity-50 disabled:cursor-not-allowed transition-all"
|
||||
aria-label="Tilni tanlash"
|
||||
aria-expanded={isOpen}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
{isPending ? (
|
||||
<Globe className="w-4 h-4 animate-spin" />
|
||||
) : (
|
||||
<span className="text-lg">{localeFlags[currentLocale]}</span>
|
||||
)}
|
||||
<span className="hidden md:inline font-medium">
|
||||
{localeNames[currentLocale]}
|
||||
</span>
|
||||
</div>
|
||||
<ChevronDown
|
||||
className={`w-4 h-4 transition-transform duration-200 ${
|
||||
isOpen ? "rotate-180" : ""
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
|
||||
{/* Dropdown */}
|
||||
{isOpen && (
|
||||
<>
|
||||
{/* Backdrop */}
|
||||
<div
|
||||
className="fixed inset-0 z-40"
|
||||
onClick={() => setIsOpen(false)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
{/* Menu */}
|
||||
<div className="absolute right-0 mt-2 w-48 rounded-lg border border-gray-200 bg-white shadow-lg z-50 animate-in fade-in slide-in-from-top-2 duration-200">
|
||||
<div className="p-1" role="menu">
|
||||
{locales.map((lang) => (
|
||||
<button
|
||||
key={lang}
|
||||
onClick={() => changeLanguage(lang)}
|
||||
disabled={isPending}
|
||||
role="menuitem"
|
||||
className={`w-full flex items-center justify-between px-3 py-2 text-sm rounded-md transition-colors ${
|
||||
currentLocale === lang
|
||||
? "bg-blue-50 text-blue-700 font-medium"
|
||||
: "hover:bg-gray-100 text-gray-700"
|
||||
} disabled:opacity-50 disabled:cursor-not-allowed`}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-lg">{localeFlags[lang]}</span>
|
||||
<span>{localeNames[lang]}</span>
|
||||
</div>
|
||||
{currentLocale === lang && (
|
||||
<Check className="w-4 h-4 text-blue-700" />
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,8 +4,13 @@ import React from "react";
|
||||
|
||||
import { useState } from "react";
|
||||
import { Mail, Phone, MapPin } from "lucide-react";
|
||||
import { useLocale, useTranslations } from "next-intl";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
export function Footer() {
|
||||
const locale = useLocale();
|
||||
const t = useTranslations();
|
||||
const [email, setEmail] = useState("");
|
||||
const [subscribed, setSubscribed] = useState(false);
|
||||
|
||||
@@ -26,16 +31,16 @@ export function Footer() {
|
||||
"linear-gradient(to top right, #452811 0%, #000000 20%, #000000 40%, #000000 60%, #000000 80%, #000000 100%)",
|
||||
}}
|
||||
>
|
||||
{/* Newsletter Section */}
|
||||
{/* Newsletter Section for gitea */}
|
||||
<div className=" absolute w-full -top-40 px-4 py-12 md:py-16">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<div className="rounded-2xl bg-[#fa1d1d] px-6 py-8 md:flex lg:flex-row flex-col max-lg:gap-5 md:items-center lg:justify-between justify-center md:px-10 md:py-12">
|
||||
<div className="mb-8 md:mb-0">
|
||||
<h2 className="text-2xl font-bold text-white md:text-3xl">
|
||||
SUBSCRIBE OUR NEWSLETTER
|
||||
<h2 className="font-unbounded text-2xl font-bold text-white md:text-3xl">
|
||||
{t("contactTitle")}
|
||||
</h2>
|
||||
<p className="mt-2 text-gray-100">
|
||||
Expect a friendly letter from us once a week. No spam.
|
||||
<p className="font-almarai mt-2 text-gray-100">
|
||||
{t("contactSubTitle")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -45,17 +50,17 @@ export function Footer() {
|
||||
>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Enter your email address"
|
||||
placeholder={t("enterPhone")}
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className="flex-1 rounded-full bg-white px-6 py-3 text-gray-800 placeholder-gray-400 focus:outline-none md:w-64"
|
||||
className="font-almarai flex-1 rounded-full bg-white px-6 py-3 text-gray-800 placeholder-gray-400 focus:outline-none md:w-64"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="rounded-full bg-gray-800 px-6 py-3 font-bold text-white transition hover:bg-gray-700"
|
||||
className="font-almarai rounded-full bg-gray-800 px-6 py-3 font-bold text-white transition hover:bg-gray-700"
|
||||
>
|
||||
{subscribed ? "✓ Sent" : "SIGN UP"}
|
||||
{subscribed ? "✓ Sent" : t("send")}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -69,91 +74,71 @@ export function Footer() {
|
||||
{/* Brand Section */}
|
||||
<div>
|
||||
<div className="mb-4 flex items-center gap-2">
|
||||
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-[#fa1d1d]">
|
||||
<span className="text-lg font-bold text-white">⚡</span>
|
||||
<div className=" flex items-center justify-center">
|
||||
<Image
|
||||
src="/images/IGNUM/PNG/1.@6x.png"
|
||||
alt="logo image"
|
||||
width={70}
|
||||
height={70}
|
||||
className=""
|
||||
/>
|
||||
</div>
|
||||
<span className="text-xl font-bold text-white">FIREFORCE</span>
|
||||
</div>
|
||||
<p className="text-sm leading-relaxed text-gray-300">
|
||||
They are seen as a beacon of hope, a figure who brings calm
|
||||
amidst chaos and light in the darkest of moments.
|
||||
<p className="font-almarai text-sm leading-relaxed text-gray-300">
|
||||
{t("footer.description")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Quick Links */}
|
||||
<div>
|
||||
<h3 className="mb-6 text-lg font-bold text-white">QUICK LINK</h3>
|
||||
<h3 className="font-unbounded uppercase mb-6 text-lg font-bold text-white">
|
||||
{t("footer.quickLinks.title")}
|
||||
</h3>
|
||||
<ul className="space-y-3 text-gray-300">
|
||||
<li>
|
||||
<a href="#home" className="transition hover:text-[#fa1d1d]">
|
||||
Home
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#about" className="transition hover:text-[#fa1d1d]">
|
||||
About
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#services"
|
||||
className="transition hover:text-[#fa1d1d]"
|
||||
<Link
|
||||
href={`/${locale}/home`}
|
||||
className="font-almarai transition hover:text-[#fa1d1d]"
|
||||
>
|
||||
Services
|
||||
</a>
|
||||
{t("footer.quickLinks.home")}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#pricing"
|
||||
className="transition hover:text-[#fa1d1d]"
|
||||
<Link
|
||||
href={`/${locale}/about`}
|
||||
className="font-almarai transition hover:text-[#fa1d1d]"
|
||||
>
|
||||
Pricing
|
||||
</a>
|
||||
{t("footer.quickLinks.about")}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#blog" className="transition hover:text-[#fa1d1d]">
|
||||
Blog
|
||||
</a>
|
||||
<Link
|
||||
href={`/${locale}/services`}
|
||||
className="font-almarai transition hover:text-[#fa1d1d]"
|
||||
>
|
||||
{t("footer.quickLinks.services")}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
href={`/${locale}/blog`}
|
||||
className="font-almarai transition hover:text-[#fa1d1d]"
|
||||
>
|
||||
{t("footer.quickLinks.products")}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Support */}
|
||||
<div>
|
||||
<h3 className="mb-6 text-lg font-bold text-white">SUPPORT</h3>
|
||||
<ul className="space-y-3 text-gray-300">
|
||||
<h3 className="font-unbounded mb-6 text-lg font-bold text-white">
|
||||
{t("footer.support.title")}
|
||||
</h3>
|
||||
<ul className="font-almarai space-y-3 text-gray-300">
|
||||
<li>
|
||||
<a href="#help" className="transition hover:text-[#fa1d1d]">
|
||||
Help Center
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#disclaimer"
|
||||
className="transition hover:text-[#fa1d1d]"
|
||||
>
|
||||
Disclaimer
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#faq" className="transition hover:text-[#fa1d1d]">
|
||||
FAQ
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#support"
|
||||
className="transition hover:text-[#fa1d1d]"
|
||||
>
|
||||
Support
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#contact"
|
||||
className="transition hover:text-[#fa1d1d]"
|
||||
>
|
||||
Contact
|
||||
{t("footer.support.contact")}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -161,12 +146,14 @@ export function Footer() {
|
||||
|
||||
{/* Contact */}
|
||||
<div>
|
||||
<h3 className="mb-6 text-lg font-bold text-white">CONTACT</h3>
|
||||
<ul className="space-y-4 text-gray-300">
|
||||
<h3 className="font-unbounded uppercase mb-6 text-lg font-bold text-white">
|
||||
{t("footer.support.contact")}
|
||||
</h3>
|
||||
<ul className="font-almarai space-y-4 text-gray-300">
|
||||
<li className="flex items-start gap-3">
|
||||
<Phone className="mt-1 h-5 w-5 shrink-0 text-white" />
|
||||
<a href="tel:+1234567890" className="hover:text-[#fa1d1d]">
|
||||
+123-456-7890
|
||||
<a href="tel:+998773722121" className="hover:text-[#fa1d1d]">
|
||||
+998-77-372-21-21
|
||||
</a>
|
||||
</li>
|
||||
<li className="flex items-start gap-3">
|
||||
@@ -191,13 +178,9 @@ export function Footer() {
|
||||
{/* Copyright Section */}
|
||||
<div className="border-t border-gray-800 px-4 py-8">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<div className="flex flex-col justify-between gap-4 text-sm text-gray-400 md:flex-row md:items-center">
|
||||
<div className="font-almarai flex flex-col justify-between gap-4 text-sm text-gray-400 md:flex-row md:items-center">
|
||||
<div>
|
||||
Copyright © 2025 Fireforce. Built with
|
||||
<span className="text-white">
|
||||
{" "}
|
||||
Guniverse WordPress Blocks Addons
|
||||
</span>
|
||||
Copyright © 2025 Ignum Company.
|
||||
</div>
|
||||
<div className="flex gap-6">
|
||||
<a href="#terms" className="hover:text-white">
|
||||
|
||||
@@ -3,8 +3,12 @@ import { useEffect, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { ChevronDown, Phone, Menu, X } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import LanguageSelectRadix from "../languageSwitcher";
|
||||
import { useLocale, useTranslations } from "next-intl";
|
||||
|
||||
export function Navbar() {
|
||||
const locale = useLocale();
|
||||
const t = useTranslations();
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
const [scrolled, setScrolled] = useState(false);
|
||||
@@ -34,9 +38,9 @@ export function Navbar() {
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex justify-between items-center h-20">
|
||||
{/* Logo */}
|
||||
<Link href="/" className="hover:cursor-pointer">
|
||||
<Link href={`/${locale}/home`} className="hover:cursor-pointer">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="p-2 rounded-xl flex items-center justify-center">
|
||||
<div className=" flex items-center justify-center">
|
||||
<Image
|
||||
src="/images/IGNUM/PNG/1.@6x.png"
|
||||
alt="logo image"
|
||||
@@ -51,25 +55,25 @@ export function Navbar() {
|
||||
{/* Desktop Navigation Menu */}
|
||||
<div className="hidden h-full lg:flex items-center gap-8">
|
||||
<Link
|
||||
href="/"
|
||||
className="text-white text-sm h-full flex items-center font-semibold hover:cursor-pointer hover:text-red-500 transition"
|
||||
href={`/${locale}/home`}
|
||||
className="font-unbounded uppercase text-white text-sm h-full flex items-center font-semibold hover:cursor-pointer hover:text-red-500 transition"
|
||||
>
|
||||
HOME
|
||||
{t("navbar.home")}
|
||||
</Link>
|
||||
<Link
|
||||
href="/about"
|
||||
className="text-white text-sm h-full flex items-center font-semibold hover:cursor-pointer hover:text-red-500 transition"
|
||||
href={`/${locale}/about`}
|
||||
className="font-unbounded uppercase text-white text-sm h-full flex items-center font-semibold hover:cursor-pointer hover:text-red-500 transition"
|
||||
>
|
||||
ABOUT
|
||||
{t("navbar.about")}
|
||||
</Link>
|
||||
|
||||
{/* Pages Dropdown */}
|
||||
<div className="relative group h-full">
|
||||
<button
|
||||
className="text-white text-sm h-full font-semibold hover:text-red-500
|
||||
className="font-unbounded uppercase text-white text-sm h-full font-semibold hover:text-red-500
|
||||
transition-colors flex items-center gap-1"
|
||||
>
|
||||
PAGES
|
||||
{t("navbar.pages")}
|
||||
<ChevronDown
|
||||
size={16}
|
||||
className="transition-transform group-hover:rotate-180"
|
||||
@@ -85,22 +89,22 @@ export function Navbar() {
|
||||
pointer-events-none group-hover:pointer-events-auto overflow-hidden"
|
||||
>
|
||||
<Link
|
||||
href="/faq"
|
||||
className="block px-4 py-2 text-black text-sm hover:bg-red-600
|
||||
href={`/${locale}/faq`}
|
||||
className="font-unbounded uppercase block px-4 py-2 text-black text-sm hover:bg-red-600
|
||||
hover:text-white transition-colors"
|
||||
>
|
||||
FAQ
|
||||
{t("navbar.faq")}
|
||||
</Link>
|
||||
<Link
|
||||
href="/services"
|
||||
className="block px-4 py-2 text-black text-sm hover:bg-red-600
|
||||
href={`/${locale}/services`}
|
||||
className="font-unbounded uppercase block px-4 py-2 text-black text-sm hover:bg-red-600
|
||||
hover:text-white transition-colors"
|
||||
>
|
||||
Services
|
||||
{t("navbar.services")}
|
||||
</Link>
|
||||
{/* <Link
|
||||
href="/blog"
|
||||
className="block px-4 py-2 text-black text-sm hover:bg-red-600
|
||||
href={`/${locale}/blog`}
|
||||
className="font-unbounded uppercase block px-4 py-2 text-black text-sm hover:bg-red-600
|
||||
hover:text-white transition-colors rounded-b-md"
|
||||
>
|
||||
Blog
|
||||
@@ -109,39 +113,46 @@ export function Navbar() {
|
||||
</div>
|
||||
|
||||
<Link
|
||||
href="/products"
|
||||
className="text-white text-sm h-full flex items-center font-semibold hover:cursor-pointer hover:text-red-500 transition"
|
||||
href={`/${locale}/products`}
|
||||
className="font-unbounded uppercase text-white text-sm h-full flex items-center font-semibold hover:cursor-pointer hover:text-red-500 transition"
|
||||
>
|
||||
PRODUCTS
|
||||
{t("navbar.products")}
|
||||
</Link>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="text-white text-sm h-full flex items-center font-semibold hover:cursor-pointer hover:text-red-500 transition"
|
||||
href={`/${locale}/contact`}
|
||||
className="font-unbounded uppercase text-white text-sm h-full flex items-center font-semibold hover:cursor-pointer hover:text-red-500 transition"
|
||||
>
|
||||
CONTACT
|
||||
{t("navbar.contact")}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Emergency Call Button - Hidden on mobile */}
|
||||
<div className="hidden lg:flex items-center gap-3 bg-red-600 px-4 py-2 rounded-full">
|
||||
<Phone size={20} className="text-white" />
|
||||
<div>
|
||||
<div className="text-white text-xs font-semibold">
|
||||
Emergency Call!
|
||||
</div>
|
||||
<div className="text-white text-sm font-bold">
|
||||
+123-456-7890
|
||||
<div className="flex items-center gap-5">
|
||||
{/* Language Switcher */}
|
||||
<LanguageSelectRadix />
|
||||
|
||||
{/* Emergency Call Button - Hidden on mobile */}
|
||||
<div className="hidden lg:flex items-center hover:cursor-pointer gap-3 px-4 py-2 rounded-full">
|
||||
<span
|
||||
className="shrink-0 w-10 h-10 bg-red-600 rounded-full flex items-center justify-center
|
||||
shadow-[0_0_0px_4px_rgba(239,68,68,0.1)]"
|
||||
>
|
||||
<Phone size={20} className="text-white" />
|
||||
</span>
|
||||
<div>
|
||||
<div className="text-white text-sm font-bold">
|
||||
<div>+998-98-099-21-21</div> <div>+998-77-372-21-21</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<button
|
||||
onClick={() => setIsMobileMenuOpen(true)}
|
||||
className="lg:hidden text-white p-2 hover:bg-red-600 rounded-md transition"
|
||||
>
|
||||
<Menu size={24} />
|
||||
</button>
|
||||
{/* Mobile Menu Button */}
|
||||
<button
|
||||
onClick={() => setIsMobileMenuOpen(true)}
|
||||
className="lg:hidden text-white p-2 hover:bg-red-600 rounded-md transition"
|
||||
>
|
||||
<Menu size={24} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -164,14 +175,20 @@ export function Navbar() {
|
||||
>
|
||||
{/* Mobile Menu Header */}
|
||||
<div className="flex justify-between items-center p-6 border-b border-gray-700">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-8 h-8 bg-red-600 rounded-full flex items-center justify-center">
|
||||
<div className="w-6 h-6 bg-white rounded-full"></div>
|
||||
{/* Logo */}
|
||||
<Link href={`/${locale}/home`} className="hover:cursor-pointer">
|
||||
<div className="font-unbounded uppercase flex flex-col items-center text-2xl gap-2 text-white font-bold">
|
||||
<div className=" flex items-center justify-center">
|
||||
<Image
|
||||
src="/images/IGNUM/PNG/1.@6x.png"
|
||||
alt="logo image"
|
||||
width={50}
|
||||
height={50}
|
||||
className=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span className="text-white font-bold text-lg tracking-wider">
|
||||
FIREFORCE
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
<button
|
||||
onClick={() => setIsMobileMenuOpen(false)}
|
||||
className="text-white p-2 hover:bg-red-600 rounded-md transition"
|
||||
@@ -183,27 +200,27 @@ export function Navbar() {
|
||||
{/* Mobile Menu Links */}
|
||||
<div className="flex flex-col p-6 gap-4">
|
||||
<Link
|
||||
href="/"
|
||||
className="text-white text-base font-semibold hover:text-red-500 transition py-2"
|
||||
href={`/${locale}/home`}
|
||||
className="font-unbounded uppercase text-white text-base font-semibold hover:text-red-500 transition py-2"
|
||||
onClick={() => setIsMobileMenuOpen(false)}
|
||||
>
|
||||
HOME
|
||||
{t("navbar.home")}
|
||||
</Link>
|
||||
<Link
|
||||
href="/about"
|
||||
className="text-white text-base font-semibold hover:text-red-500 transition py-2"
|
||||
href={`/${locale}/about`}
|
||||
className="font-unbounded uppercase text-white text-base font-semibold hover:text-red-500 transition py-2"
|
||||
onClick={() => setIsMobileMenuOpen(false)}
|
||||
>
|
||||
ABOUT
|
||||
{t("navbar.about")}
|
||||
</Link>
|
||||
|
||||
{/* Mobile Pages Dropdown */}
|
||||
<div>
|
||||
<button
|
||||
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
|
||||
className="text-white text-base font-semibold hover:text-red-500 transition flex items-center gap-1 py-2 w-full"
|
||||
className="font-unbounded uppercase text-white text-base font-semibold hover:text-red-500 transition flex items-center gap-1 py-2 w-full"
|
||||
>
|
||||
PAGES
|
||||
{t("navbar.pages")}
|
||||
<ChevronDown
|
||||
size={16}
|
||||
className={`transition-transform ${isDropdownOpen ? "rotate-180" : ""}`}
|
||||
@@ -212,36 +229,36 @@ export function Navbar() {
|
||||
{isDropdownOpen && (
|
||||
<div className="ml-4 mt-2 flex flex-col gap-2">
|
||||
<Link
|
||||
href="/faq"
|
||||
className="text-white/80 text-sm hover:text-red-500 transition py-2"
|
||||
href={`/${locale}/faq`}
|
||||
className="font-unbounded uppercase text-white/80 text-sm hover:text-red-500 transition py-2"
|
||||
onClick={() => setIsMobileMenuOpen(false)}
|
||||
>
|
||||
FAQ
|
||||
{t("navbar.faq")}
|
||||
</Link>
|
||||
<Link
|
||||
href="/services"
|
||||
className="text-white/80 text-sm hover:text-red-500 transition py-2"
|
||||
href={`/${locale}/services`}
|
||||
className="font-unbounded uppercase text-white/80 text-sm hover:text-red-500 transition py-2"
|
||||
onClick={() => setIsMobileMenuOpen(false)}
|
||||
>
|
||||
Services
|
||||
{t("navbar.services")}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Link
|
||||
href="/products"
|
||||
className="text-white text-base font-semibold hover:text-red-500 transition py-2"
|
||||
href={`/${locale}/products`}
|
||||
className="font-unbounded uppercase text-white text-base font-semibold hover:text-red-500 transition py-2"
|
||||
onClick={() => setIsMobileMenuOpen(false)}
|
||||
>
|
||||
PRODUCTS
|
||||
{t("navbar.products")}
|
||||
</Link>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="text-white text-base font-semibold hover:text-red-500 transition py-2"
|
||||
href={`/${locale}/contact`}
|
||||
className="font-unbounded uppercase text-white text-base font-semibold hover:text-red-500 transition py-2"
|
||||
onClick={() => setIsMobileMenuOpen(false)}
|
||||
>
|
||||
CONTACT
|
||||
{t("navbar.contact")}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export function AboutBanner() {
|
||||
const t = useTranslations();
|
||||
return (
|
||||
<section className="relative w-full lg:h-[60vh] h-screen min-h-100 overflow-hidden pt-10">
|
||||
{/* Background Image */}
|
||||
@@ -24,17 +26,21 @@ export function AboutBanner() {
|
||||
<div className="max-w-250 w-full mx-auto px-4">
|
||||
<div className="relative z-20 h-full flex max-lg:flex-col items-start justify-between gap-5 pt-30">
|
||||
<div className="spacw-y-4 ">
|
||||
<DotAnimatsiya />
|
||||
<div className="flex items-center gap-3">
|
||||
<DotAnimatsiya />
|
||||
<span className="font-almarai text-sm text-white font-semibold tracking-wide">
|
||||
{t("about.banner.title")}
|
||||
</span>
|
||||
</div>
|
||||
<p
|
||||
className=" bg-linear-to-br from-white via-white to-black
|
||||
className="font-unbounded uppercase bg-linear-to-br from-white via-white to-black
|
||||
text-transparent bg-clip-text text-4xl sm:text-5xl lg:text-6xl font-bold leading-tight text-pretty"
|
||||
>
|
||||
Fire Fighter <br /> At The Ready
|
||||
{t("about.banner.subtitle")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="lg:w-[40%] text-gray-300 mt-20">
|
||||
It emphasizes that these firefighters are there not just as public
|
||||
servants but as a vital part of the community.
|
||||
<div className="font-almarai lg:w-[40%] text-gray-300 mt-20">
|
||||
{t("about.banner.description")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useTranslations } from "next-intl";
|
||||
import Image from "next/image";
|
||||
|
||||
export function Story() {
|
||||
const t = useTranslations();
|
||||
return (
|
||||
<div className="bg-[#1e1d1c] pb-0 relative z-10 max-[350px]:pb-30 ">
|
||||
<div className="max-w-260 mx-auto px-4">
|
||||
@@ -25,22 +27,14 @@ export function Story() {
|
||||
|
||||
{/* Content */}
|
||||
<div className="relative z-20 p-8 lg:p-12 max-w-130">
|
||||
<h2 className="text-white text-4xl lg:text-5xl font-bold mb-6">
|
||||
OUR STORY
|
||||
<h2 className="uppercase font-unbounded text-white text-4xl lg:text-5xl font-bold mb-6">
|
||||
{t("about.story.title")}
|
||||
</h2>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Our story is one of unwavering dedication, selflessness, and a{" "}
|
||||
<span className="text-white font-semibold">
|
||||
deep commitment to the safety
|
||||
</span>
|
||||
and well-being of our communities.
|
||||
<p className="font-almarai text-gray-300 mb-4">
|
||||
{t("about.story.description")}
|
||||
</p>
|
||||
<p className="text-gray-400 mb-6">
|
||||
Aliquam lorem ante dapibus in viverra quis a tellus phasellus
|
||||
viverra nulla ut metus varius laoreet quisque rutrum.
|
||||
</p>
|
||||
<button className="text-white flex items-center gap-2 hover:text-red-500 transition">
|
||||
READ MORE
|
||||
<button className="font-almarai text-white flex items-center gap-2 hover:text-red-500 transition">
|
||||
{t("about.story.readMore")}
|
||||
<svg
|
||||
className="w-4 h-4"
|
||||
fill="none"
|
||||
@@ -74,14 +68,15 @@ export function Story() {
|
||||
/>
|
||||
</span>
|
||||
<div className="space-y-1 text-white">
|
||||
<h2 className="text-xl font-semibold">FIREFORCE VISION</h2>
|
||||
<p>
|
||||
Phasellus viverra nulla ut metus varius leo imperdiet laoreet.
|
||||
Quisque rutrum aenean augue vulputate eleifend.
|
||||
<h2 className="font-unbounded text-xl font-semibold">
|
||||
{t("about.story.vision.title")}
|
||||
</h2>
|
||||
<p className="font-almarai">
|
||||
{t("about.story.vision.description")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex sm:flex-row flex-col sm:items-center items-start md:rounded-t-xl max-md:rounded-xl max-w-md w-full sm:p-7 p-2 bg-black sm:gap-5 gap-2">
|
||||
<div className="flex sm:flex-row flex-col sm:items-center items-start md:rounded-t-xl max-md:rounded-xl max-w-md w-full sm:p-4 p-2 bg-black sm:gap-5 gap-2">
|
||||
<span className="sm:rounded-xl rounded-lg bg-[#1e1d1c] sm:p-3 p-1 max-sm:w-15 max-sm:h-15">
|
||||
<Image
|
||||
src="/images/about/fireforce-mission.png"
|
||||
@@ -92,10 +87,11 @@ export function Story() {
|
||||
/>
|
||||
</span>
|
||||
<div className="space-y-1 text-white">
|
||||
<h2 className="text-xl font-semibold">FIREFORCE VISION</h2>
|
||||
<p>
|
||||
Phasellus viverra nulla ut metus varius leo imperdiet laoreet.
|
||||
Quisque rutrum aenean augue vulputate eleifend.
|
||||
<h2 className="font-unbounded text-xl font-semibold">
|
||||
{t("about.story.mission.title")}
|
||||
</h2>
|
||||
<p className="font-almarai">
|
||||
{t("about.story.mission.description")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
import Image from "next/image";
|
||||
import { Check } from "lucide-react";
|
||||
import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export function WhyChooseUs() {
|
||||
const t = useTranslations();
|
||||
const features = [
|
||||
{ title: "Fast Response Team" },
|
||||
{ title: "Experienced Firefighter" },
|
||||
{ title: "Ready 24 Hours" },
|
||||
{ title: "Fast Response Team" },
|
||||
{ title: t("about.whyChoose.features.fastResponse") },
|
||||
{ title: t("about.whyChoose.features.ready24") },
|
||||
{ title: t("about.whyChoose.features.experienced") },
|
||||
{ title: t("about.whyChoose.features.quality") },
|
||||
];
|
||||
|
||||
return (
|
||||
@@ -21,24 +23,21 @@ export function WhyChooseUs() {
|
||||
<div>
|
||||
<div className="mb-4 flex items-center gap-2">
|
||||
<DotAnimatsiya />
|
||||
<span className="text-sm font-semibold tracking-wider text-white">
|
||||
WHY CHOOSE US
|
||||
<span className="font-almarai text-sm font-semibold tracking-wider text-white">
|
||||
{t("about.whyChoose.title")}
|
||||
</span>
|
||||
</div>
|
||||
<h2
|
||||
className="bg-linear-to-br from-white via-white to-black
|
||||
text-transparent bg-clip-text text-4xl font-bold sm:text-5xl lg:text-6xl"
|
||||
className="font-unbounded uppercase bg-linear-to-br from-white via-white to-black
|
||||
text-transparent bg-clip-text text-3xl font-bold sm:text-4xl lg:text-5xl"
|
||||
>
|
||||
WE ARE BEST
|
||||
<br />
|
||||
FIREFIGHTER
|
||||
{t("about.whyChoose.subtitle")}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<p className="text-base leading-relaxed text-gray-400 sm:text-lg">
|
||||
Aliquam lorem ante dapibus in viverra quis a tellus phasellus
|
||||
viverra nulla ut metus varius laoreet quisque rutrum.
|
||||
<p className="font-almarai text-base leading-relaxed text-gray-400 sm:text-lg">
|
||||
{t("about.whyChoose.description")}
|
||||
</p>
|
||||
|
||||
{/* Features Grid */}
|
||||
@@ -48,7 +47,7 @@ export function WhyChooseUs() {
|
||||
<div className="shrink-0">
|
||||
<Check className="h-5 w-5 text-red-600 sm:h-6 sm:w-6" />
|
||||
</div>
|
||||
<span className="text-sm font-medium text-white sm:text-base">
|
||||
<span className="font-almarai text-sm font-medium text-white sm:text-base">
|
||||
{feature.title}
|
||||
</span>
|
||||
</div>
|
||||
@@ -57,8 +56,8 @@ export function WhyChooseUs() {
|
||||
|
||||
{/* CTA Button */}
|
||||
<div>
|
||||
<button className="shadow-[0px_0px_2px_8px_#ff01015c] rounded-full bg-red-600 px-6 py-3 font-bold text-white transition-all hover:bg-red-700 sm:px-8 sm:py-4">
|
||||
CONTACT US
|
||||
<button className="font-almarai shadow-[0px_0px_2px_8px_#ff01015c] rounded-full bg-red-600 px-6 py-3 font-bold text-white transition-all hover:bg-red-700 sm:px-8 sm:py-4">
|
||||
{t("about.whyChoose.contact")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,11 +86,8 @@ export function WhyChooseUs() {
|
||||
className="h-24 w-24 sm:h-20 sm:w-20"
|
||||
/>
|
||||
<div>
|
||||
<p className="text-sm font-bold text-white sm:text-base">
|
||||
BEST AWARD
|
||||
</p>
|
||||
<p className="text-xs text-gray-400 sm:text-sm">
|
||||
FIREFIGHTER 2025
|
||||
<p className="font-almarai text-sm font-bold text-white sm:text-base">
|
||||
{t("about.whyChoose.award")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
|
||||
import { useTranslations } from "next-intl";
|
||||
import React from "react";
|
||||
|
||||
export default function ContactHeader() {
|
||||
const t = useTranslations();
|
||||
return (
|
||||
<div className="mb-8 text-center">
|
||||
<div className="mb-4 flex items-center justify-center gap-2">
|
||||
<DotAnimatsiya />
|
||||
<span className="text-sm font-semibold tracking-wider text-white">
|
||||
CONTACT US
|
||||
<span className="font-almarai text-sm font-semibold tracking-wider text-white">
|
||||
{t("contact.banner.title")}
|
||||
</span>
|
||||
</div>
|
||||
<h2
|
||||
className="bg-linear-to-br from-white via-white to-black
|
||||
className="uppercase font-unbounded bg-linear-to-br from-white via-white to-black
|
||||
text-transparent bg-clip-text text-4xl font-bold tracking-wide md:text-5xl"
|
||||
>
|
||||
GET IN TOUCH
|
||||
{t("contact.banner.subtitle")}
|
||||
</h2>
|
||||
<p className="mt-3 text-sm text-gray-300 italic">
|
||||
We'd love to hear from you. Please fill out this form.
|
||||
<p className="font-almarai mt-3 text-sm text-gray-300 italic">
|
||||
{t("contact.banner.description")}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Check } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useState } from "react";
|
||||
|
||||
interface FormData {
|
||||
@@ -22,6 +23,7 @@ interface FormErrors {
|
||||
}
|
||||
|
||||
export default function Form() {
|
||||
const t = useTranslations();
|
||||
const [formData, setFormData] = useState<FormData>({
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
@@ -124,30 +126,31 @@ export default function Form() {
|
||||
<input
|
||||
type="text"
|
||||
name="firstName"
|
||||
placeholder="First Name"
|
||||
placeholder={t("contact.form.placeholders.firstName")}
|
||||
value={formData.firstName}
|
||||
onChange={handleChange}
|
||||
className={`w-full rounded-3xl border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||
className={`font-almarai w-full rounded-3xl border bg-white px-4 py-3 text-sm
|
||||
text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||
errors.firstName ? "border-red-500" : "border-transparent"
|
||||
}`}
|
||||
/>
|
||||
{errors.firstName && (
|
||||
<p className="mt-1 text-xs text-red-500">{errors.firstName}</p>
|
||||
<p className="font-almarai mt-1 text-xs text-red-500">{errors.firstName}</p>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
name="lastName"
|
||||
placeholder="Last Name"
|
||||
placeholder={t("contact.form.placeholders.lastName")}
|
||||
value={formData.lastName}
|
||||
onChange={handleChange}
|
||||
className={`w-full rounded-3xl border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||
className={`font-almarai w-full rounded-3xl border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||
errors.lastName ? "border-red-500" : "border-transparent"
|
||||
}`}
|
||||
/>
|
||||
{errors.lastName && (
|
||||
<p className="mt-1 text-xs text-red-500">{errors.lastName}</p>
|
||||
<p className="font-almarai mt-1 text-xs text-red-500">{errors.lastName}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -158,30 +161,30 @@ export default function Form() {
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Your Email Address"
|
||||
placeholder={t("contact.form.placeholders.email")}
|
||||
value={formData.email}
|
||||
onChange={handleChange}
|
||||
className={`w-full rounded-3xl border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||
className={`font-almarai w-full rounded-3xl border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||
errors.email ? "border-red-500" : "border-transparent"
|
||||
}`}
|
||||
/>
|
||||
{errors.email && (
|
||||
<p className="mt-1 text-xs text-red-500">{errors.email}</p>
|
||||
<p className="font-almarai mt-1 text-xs text-red-500">{errors.email}</p>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
name="subject"
|
||||
placeholder="Subject"
|
||||
placeholder={t("contact.form.placeholders.subject")}
|
||||
value={formData.subject}
|
||||
onChange={handleChange}
|
||||
className={`w-full rounded-3xl border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||
className={`font-almarai w-full rounded-3xl border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||
errors.subject ? "border-red-500" : "border-transparent"
|
||||
}`}
|
||||
/>
|
||||
{errors.subject && (
|
||||
<p className="mt-1 text-xs text-red-500">{errors.subject}</p>
|
||||
<p className="font-almarai mt-1 text-xs text-red-500">{errors.subject}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -190,16 +193,16 @@ export default function Form() {
|
||||
<div>
|
||||
<textarea
|
||||
name="message"
|
||||
placeholder="Leave us a message"
|
||||
placeholder={t("contact.form.placeholders.message")}
|
||||
rows={8}
|
||||
value={formData.message}
|
||||
onChange={handleChange}
|
||||
className={`w-full resize-none rounded-md border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||
className={`font-almarai w-full resize-none rounded-md border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||
errors.message ? "border-red-500" : "border-transparent"
|
||||
}`}
|
||||
/>
|
||||
{errors.message && (
|
||||
<p className="mt-1 text-xs text-red-500">{errors.message}</p>
|
||||
<p className="font-almarai mt-1 text-xs text-red-500">{errors.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -220,30 +223,30 @@ export default function Form() {
|
||||
<Check className="h-3 w-3 text-white" strokeWidth={3} />
|
||||
)}
|
||||
</button>
|
||||
<span className="text-sm text-gray-300">
|
||||
You agree to our friendly privacy policy
|
||||
<span className="font-almarai text-sm text-gray-300">
|
||||
{t("contact.form.privacy")}
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="shadow-[0px_0px_2px_8px_#ff01015c] rounded-full bg-red-600 px-8 py-3 text-sm font-semibold uppercase tracking-wider text-white transition hover:cursor-pointer hover:scale-90 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className="font-almarai shadow-[0px_0px_2px_8px_#ff01015c] rounded-full bg-red-600 px-8 py-3 text-sm font-semibold uppercase tracking-wider text-white transition hover:cursor-pointer hover:scale-90 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
{isSubmitting ? "Sending..." : "Send Message"}
|
||||
{isSubmitting ? "Sending..." : t("contact.form.send")}
|
||||
</button>
|
||||
</div>
|
||||
{errors.agreeToPolicy && (
|
||||
<p className="text-xs text-red-500">{errors.agreeToPolicy}</p>
|
||||
<p className="font-almarai text-xs text-red-500">{errors.agreeToPolicy}</p>
|
||||
)}
|
||||
|
||||
{/* Status Messages */}
|
||||
{submitStatus === "success" && (
|
||||
<p className="text-center text-sm text-green-400">
|
||||
<p className="font-almarai text-center text-sm text-green-400">
|
||||
Message sent successfully!
|
||||
</p>
|
||||
)}
|
||||
{submitStatus === "error" && (
|
||||
<p className="text-center text-sm text-red-400">
|
||||
<p className="font-almarai text-center text-sm text-red-400">
|
||||
Failed to send message. Please try again.
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -2,23 +2,25 @@ import Image from "next/image";
|
||||
import { Mail, MapPin, Phone, Check } from "lucide-react";
|
||||
import ContactHeader from "./contactHeader";
|
||||
import Form from "./form";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export function Contact() {
|
||||
const t = useTranslations();
|
||||
const contactInfo = [
|
||||
{
|
||||
icon: Mail,
|
||||
title: "EMAIL",
|
||||
detail: "support@fireforce",
|
||||
title:t("contact.form.email"),
|
||||
detail: t("contact.form.emailAddress"),
|
||||
},
|
||||
{
|
||||
icon: MapPin,
|
||||
title: "OUR LOCATION",
|
||||
detail: "Jl. Dr. Ir. Soekarno No. 99x Tabanan - Bali",
|
||||
title: t("contact.form.location"),
|
||||
detail: t("contact.form.address"),
|
||||
},
|
||||
{
|
||||
icon: Phone,
|
||||
title: "PHONE",
|
||||
detail: "+123-456-7890",
|
||||
title: t("contact.form.phone"),
|
||||
detail: "+998-77-372-21-21",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -38,7 +40,7 @@ export function Contact() {
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
background:
|
||||
"radial-gradient(ellipse at bottom center, #d2610ab0 0%, #1e1d1ce3 70%)",
|
||||
"radial-gradient(ellipse at bottom center, #d2610a 0%, #1e1d1ce9 70% , #1e1d1ce9 70%)",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -59,10 +61,10 @@ export function Contact() {
|
||||
<div className="mb-3 flex h-14 w-14 items-center justify-center rounded-xl bg-[#2c2b2a]">
|
||||
<info.icon className="h-6 w-6 text-red-600" />
|
||||
</div>
|
||||
<h3 className="text-sm font-bold tracking-wider text-white">
|
||||
<h3 className="font-almarai text-sm font-bold tracking-wider text-white">
|
||||
{info.title}
|
||||
</h3>
|
||||
<p className="mt-1 text-sm text-gray-400">{info.detail}</p>
|
||||
<p className="font-almarai mt-1 text-sm text-gray-400">{info.detail}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -1,44 +1,73 @@
|
||||
import Link from "next/link";
|
||||
import FAQAccordion from "./faqAccardion";
|
||||
import { faqItems } from "@/lib/demoData";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export function Togle() {
|
||||
const t = useTranslations();
|
||||
const faqItems = [
|
||||
{
|
||||
id: "faq-1",
|
||||
question: t("faq.question1.question"),
|
||||
answer: t("faq.question1.answer"),
|
||||
},
|
||||
{
|
||||
id: "faq-2",
|
||||
question: t("faq.question2.question"),
|
||||
answer: t("faq.question2.answer"),
|
||||
},
|
||||
{
|
||||
id: "faq-3",
|
||||
question: t("faq.question3.question"),
|
||||
answer: t("faq.question3.answer"),
|
||||
},
|
||||
{
|
||||
id: "faq-4",
|
||||
question: t("faq.question4.question"),
|
||||
answer: t("faq.question4.answer"),
|
||||
},
|
||||
{
|
||||
id: "faq-5",
|
||||
question: t("faq.question5.question"),
|
||||
answer: t("faq.question5.answer"),
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div className="min-h-screen bg-[#1e1d1c]">
|
||||
<main className="mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:px-8">
|
||||
{/* Header Section */}
|
||||
<div className="mb-16 flex items-start justify-between gap-8 lg:gap-12">
|
||||
<div className="mb-16 flex items-start justify-between gap-4 lg:gap-12">
|
||||
<div className="flex items-center md:col-span-1">
|
||||
<h1
|
||||
className="bg-linear-to-br from-white via-white/50 to-black
|
||||
text-transparent bg-clip-text text-3xl font-bold uppercase leading-tight sm:text-4xl md:text-5xl lg:text-6xl"
|
||||
className="font-unbounded uppercase bg-linear-to-br from-white via-white/50 to-black
|
||||
text-transparent bg-clip-text text-3xl font-bold leading-tight sm:text-4xl md:text-5xl lg:text-6xl"
|
||||
>
|
||||
About <br /> Work
|
||||
{t("faq.banner.topic")}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{/* FAQ Section */}
|
||||
<div className="md:col-span-2">
|
||||
<div className="max-w-250 w-full">
|
||||
<FAQAccordion items={faqItems} />
|
||||
</div>
|
||||
</div>
|
||||
{/* ASK QUESTION */}
|
||||
<div className="space-y-8 w-full mt-10 ">
|
||||
<h1
|
||||
className="text-center bg-linear-to-br from-white via-white/50 to-black
|
||||
text-transparent bg-clip-text text-3xl font-bold uppercase leading-tight sm:text-4xl md:text-5xl lg:text-6xl"
|
||||
className="font-unbounded uppercase text-center bg-linear-to-br from-white via-white/50 to-black
|
||||
text-transparent bg-clip-text text-3xl font-bold leading-tight sm:text-4xl md:text-5xl lg:text-6xl"
|
||||
>
|
||||
Still Have Question?
|
||||
{t("faq.ask.question")}
|
||||
</h1>
|
||||
<p className="text-center text-white/80 text-lg">
|
||||
Nullam dictum felis eu pede mollis pretium integer tincidunt.
|
||||
<p className="font-almarai text-center text-white/80 text-lg">
|
||||
{t("faq.ask.subtitle")}
|
||||
</p>
|
||||
<div className="w-full flex items-center justify-center">
|
||||
<Link
|
||||
href={"/contact"}
|
||||
className="mx-auto shadow-[0px_0px_2px_8px_#ff01015c] bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-8 rounded-full transition duration-300 transform hover:scale-105 w-fit"
|
||||
className="font-almarai mx-auto shadow-[0px_0px_2px_8px_#ff01015c] bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-8 rounded-full transition duration-300 transform hover:scale-105 w-fit"
|
||||
>
|
||||
ASK A QUESTION
|
||||
{t("faq.ask.btn")}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function FAQAccordion({ items }: FAQAccordionProps) {
|
||||
{items.map((item, index) => (
|
||||
<Accordion.Item key={item.id} value={item.id} className="border-b border-slate-700 py-6">
|
||||
<Accordion.Trigger className="group flex w-full items-center justify-between text-left">
|
||||
<h3 className="text-lg font-bold uppercase tracking-wide text-white transition-colors duration-300 group-hover:cursor-pointer md:text-xl">
|
||||
<h3 className="font-almarai text-lg font-bold uppercase tracking-wide text-white transition-colors duration-300 group-hover:cursor-pointer md:text-xl">
|
||||
{item.question}
|
||||
</h3>
|
||||
<div className="ml-4 shrink-0">
|
||||
@@ -31,7 +31,7 @@ export default function FAQAccordion({ items }: FAQAccordionProps) {
|
||||
</Accordion.Trigger>
|
||||
|
||||
<Accordion.Content className="overflow-hidden pt-4 text-gray-400 animate-in fade-in slide-in-from-top-2 duration-300 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=closed]:slide-out-to-top-2">
|
||||
<p className="leading-relaxed text-sm md:text-base">{item.answer}</p>
|
||||
<p className="font-almarai leading-relaxed text-sm md:text-base">{item.answer}</p>
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
))}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export function FaqBanner() {
|
||||
const t = useTranslations();
|
||||
return (
|
||||
<section className="relative w-full h-[55vh] min-h-100 overflow-hidden pt-10">
|
||||
{/* Background Image */}
|
||||
@@ -24,12 +26,17 @@ export function FaqBanner() {
|
||||
<div className="max-w-250 w-full mx-auto px-4">
|
||||
<div className="relative z-20 h-full flex max-lg:flex-col items-start justify-between gap-5 pt-30">
|
||||
<div className="spacw-y-4 ">
|
||||
<DotAnimatsiya />
|
||||
<div className="flex items-center gap-3">
|
||||
<DotAnimatsiya />
|
||||
<span className="font-almarai text-sm text-white font-semibold tracking-wide">
|
||||
{t("faq.banner.title")}
|
||||
</span>
|
||||
</div>
|
||||
<p
|
||||
className=" bg-linear-to-br from-white via-white to-black
|
||||
className="font-unbounded uppercase bg-linear-to-br from-white via-white to-black
|
||||
text-transparent bg-clip-text text-4xl sm:text-5xl lg:text-6xl font-bold leading-tight text-pretty"
|
||||
>
|
||||
GENERAL <br /> QUESTIONS
|
||||
{t("faq.banner.subtitle")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Button } from "@/components/ui/button";
|
||||
import Image from "next/image";
|
||||
import { Flame, Building2, Ambulance } from "lucide-react";
|
||||
import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
interface ServiceItem {
|
||||
icon: React.ReactNode;
|
||||
@@ -13,28 +14,25 @@ interface ServiceItem {
|
||||
description: string;
|
||||
}
|
||||
|
||||
const services: ServiceItem[] = [
|
||||
{
|
||||
icon: <Flame width={40} height={40} className="text-red-500" />,
|
||||
title: "FIRE PREVENTION",
|
||||
description:
|
||||
"Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum aenean imperdiet augue",
|
||||
},
|
||||
{
|
||||
icon: <Building2 width={40} height={40} className="text-red-500" />,
|
||||
title: "ACTIVE ACCIDENTS",
|
||||
description:
|
||||
"Nullam dictum felis eu pede mollis pretium. Integer tincidunt cras dapibus vivamus consequat vitae.",
|
||||
},
|
||||
{
|
||||
icon: <Ambulance width={40} height={40} className="text-red-500" />,
|
||||
title: "AMBULANCE SERVICE",
|
||||
description:
|
||||
"Donec pede justo fringilla vel aliquet nec vulputate eget arcu enim justo rhoncus ut venenatis.",
|
||||
},
|
||||
];
|
||||
|
||||
export function AboutUs() {
|
||||
const t = useTranslations();
|
||||
const services: ServiceItem[] = [
|
||||
{
|
||||
icon: <Flame width={40} height={40} className="text-red-500" />,
|
||||
title: t("home.about.prevention.title"),
|
||||
description: t("home.about.prevention.description"),
|
||||
},
|
||||
{
|
||||
icon: <Building2 width={40} height={40} className="text-red-500" />,
|
||||
title: t("home.about.accidents.title"),
|
||||
description: t("home.about.accidents.description"),
|
||||
},
|
||||
{
|
||||
icon: <Ambulance width={40} height={40} className="text-red-500" />,
|
||||
title: t("home.about.service.title"),
|
||||
description: t("home.about.service.description"),
|
||||
},
|
||||
];
|
||||
return (
|
||||
<section className="bg-[#1e1d1c] py-16 px-4 sm:py-20 sm:px-6 lg:px-8">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
@@ -45,17 +43,15 @@ export function AboutUs() {
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<DotAnimatsiya />
|
||||
<span className="text-white font-bold text-sm tracking-wide">
|
||||
ABOUT US
|
||||
<span className="font-almarai text-white font-bold text-sm tracking-wide">
|
||||
{t("home.about.title")}
|
||||
</span>
|
||||
</div>
|
||||
<h2
|
||||
className="text-4xl bg-linear-to-br from-white via-white to-black
|
||||
className="font-unbounded uppercase text-4xl bg-linear-to-br from-white via-white to-black
|
||||
text-transparent bg-clip-text sm:text-5xl lg:text-6xl font-bold leading-tight"
|
||||
>
|
||||
FIREFIGHTERS
|
||||
<br />
|
||||
AT THE READY
|
||||
{t("home.about.subtitle")}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
@@ -67,10 +63,10 @@ export function AboutUs() {
|
||||
{service.icon}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-white font-bold text-base sm:text-lg mb-2">
|
||||
<h3 className="uppercase font-unbounded text-white font-bold text-base sm:text-lg mb-2">
|
||||
{service.title}
|
||||
</h3>
|
||||
<p className="text-gray-400 text-sm sm:text-base leading-relaxed">
|
||||
<p className="font-almarai text-gray-400 text-sm sm:text-base leading-relaxed">
|
||||
{service.description}
|
||||
</p>
|
||||
</div>
|
||||
@@ -80,8 +76,8 @@ export function AboutUs() {
|
||||
|
||||
{/* Button */}
|
||||
<div>
|
||||
<Button className="bg-red-600 hover:bg-red-700 text-white font-bold px-8 py-3 rounded-full transition-colors duration-300 shadow-[0px_0px_2px_8px_#ff01015c]">
|
||||
ABOUT US
|
||||
<Button className="font-almarai bg-red-600 hover:bg-red-700 text-white font-bold px-8 py-3 rounded-full transition-colors duration-300 shadow-[0px_0px_2px_8px_#ff01015c]">
|
||||
{t("home.about.title")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -112,10 +108,7 @@ export function AboutUs() {
|
||||
/>
|
||||
<div className="text-center">
|
||||
<p className="text-white font-bold text-sm sm:text-base">
|
||||
BEST AWARD
|
||||
</p>
|
||||
<p className="text-white font-bold text-sm sm:text-base">
|
||||
FIREFIGHTER 2025
|
||||
{t("home.about.award")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useTranslations } from "next-intl";
|
||||
import DotAnimatsiya from "../../dot/DotAnimatsiya";
|
||||
|
||||
export function Banner() {
|
||||
const t = useTranslations();
|
||||
return (
|
||||
<section className="relative w-full lg:h-[86vh] h-screen min-h-150 overflow-hidden pt-20">
|
||||
{/* Background Image */}
|
||||
@@ -17,78 +19,77 @@ export function Banner() {
|
||||
<div
|
||||
className="absolute inset-0 z-10"
|
||||
style={{
|
||||
background: `linear-gradient(to top right, #d2610ab0 0%, #1e1d1ce3 20%, #1e1d1ce3 100%)`,
|
||||
background: `linear-gradient(to top right, #c75c08 0%, #1e1d1ce3 28%, #1e1d1ce3 100%)`,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Content Container */}
|
||||
<div className="relative z-20 h-full flex items-end lg:mt-0 md:mt-[15vh] sm:mt-[5vh] mt-0">
|
||||
<div className="max-w-375 mx-auto px-4 sm:px-6 lg:px-8 w-full">
|
||||
<div className="relative z-20 h-full flex items-center lg:mt-0 sm:mt-[10vh] mt-[5vh]">
|
||||
<div className="max-w-400 mx-auto px-4 sm:px-6 lg:px-8 w-full">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 lg:gap-12 items-center h-full">
|
||||
{/* Right side - Text Content */}
|
||||
<div className="lg:hidden inline-block space-y-6 text-white">
|
||||
{/* Badge */}
|
||||
<div className="flex items-center gap-2 w-fit">
|
||||
<DotAnimatsiya />
|
||||
<span className="text-sm font-semibold tracking-wide">
|
||||
WELCOME TO FIREFORCE
|
||||
<span className="text-sm font-semibold tracking-wide font-almarai">
|
||||
{t("home.banner.title1")}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Main Heading */}
|
||||
<h1
|
||||
className="bg-linear-to-br from-white via-white to-black
|
||||
text-transparent bg-clip-text text-4xl sm:text-5xl lg:text-6xl font-bold leading-tight text-pretty"
|
||||
text-transparent bg-clip-text text-4xl sm:text-5xl lg:text-6xl font-bold leading-tight text-pretty font-unbounded"
|
||||
>
|
||||
THE FIRE GUARDIAN
|
||||
{t("home.banner.title2")}
|
||||
</h1>
|
||||
|
||||
{/* Description */}
|
||||
<p className="text-base sm:text-lg text-gray-300 leading-relaxed max-w-md">
|
||||
They are seen as a beacon of hope, a figure who brings calm
|
||||
amidst chaos and light in the darkest of moments.
|
||||
{t("home.banner.description")}
|
||||
</p>
|
||||
|
||||
{/* CTA Button */}
|
||||
<button className="shadow-[0px_0px_2px_8px_#ff01015c] bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-8 rounded-full transition duration-300 transform hover:scale-105 w-fit">
|
||||
GET STARTED
|
||||
{t("home.banner.cta")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Left side - Firefighters Image */}
|
||||
<div className="flex items-end justify-center">
|
||||
<div className="flex items-end justify-center ">
|
||||
<img
|
||||
src="/images/home/bannerHuman.png"
|
||||
src="/images/homeBanner.png"
|
||||
alt="Firefighters"
|
||||
loading="lazy"
|
||||
className="w-full max-lg:w-[80vw] h-auto object-cover drop-shadow-2xl"
|
||||
className="lg:w-150 w-100 lg:h-150 max-[300px]:w-[80vw] object-cover object-right rounded-xl drop-shadow-2xl"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Right side - Text Content */}
|
||||
<div className="lg:inline-block hidden space-y-6 text-white mb-20">
|
||||
<div className="lg:inline-block hidden space-y-6 mb-20">
|
||||
{/* Badge */}
|
||||
<div className="flex items-center gap-2 w-fit">
|
||||
<DotAnimatsiya />
|
||||
<span className="text-sm font-semibold tracking-wide">
|
||||
WELCOME TO FIREFORCE
|
||||
<span className="text-sm font-semibold text-white tracking-wide font-almarai">
|
||||
{t("home.banner.title1")}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Main Heading */}
|
||||
<h1 className="gradient-text text-4xl sm:text-5xl lg:text-6xl font-bold leading-tight text-pretty">
|
||||
THE FIRE GUARDIAN
|
||||
<h1 className="font-unbounded uppercase text-4xl bg-linear-to-br from-white via-white to-black
|
||||
text-transparent bg-clip-text sm:text-5xl lg:text-6xl font-bold leading-tight text-pretty">
|
||||
{t("home.banner.title2")}
|
||||
</h1>
|
||||
|
||||
{/* Description */}
|
||||
<p className="text-base sm:text-lg text-gray-300 leading-relaxed max-w-md">
|
||||
They are seen as a beacon of hope, a figure who brings calm
|
||||
amidst chaos and light in the darkest of moments.
|
||||
<p className="font-almarai text-base sm:text-lg text-gray-300 leading-relaxed max-w-md">
|
||||
{t("home.banner.description")}
|
||||
</p>
|
||||
|
||||
{/* CTA Button */}
|
||||
<button className="shadow-[0px_0px_2px_8px_#ff01015c] bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-8 rounded-full transition duration-300 transform hover:scale-105 w-fit">
|
||||
GET STARTED
|
||||
<button className="font-almarai shadow-[0px_0px_2px_8px_#ff01015c] bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-8 rounded-full transition duration-300 transform hover:scale-105 w-fit">
|
||||
{t("home.banner.cta")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,35 +1,38 @@
|
||||
import Image from "next/image";
|
||||
import { ChevronRight } from "lucide-react";
|
||||
import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
|
||||
|
||||
const blogPosts = [
|
||||
{
|
||||
id: 1,
|
||||
image: "/images/img14.webp",
|
||||
category: "Tips & Trick",
|
||||
title: "BEHIND THE HELMET: LIFE AS A FIREFIGHTER",
|
||||
author: "John Doe",
|
||||
date: "July 24, 2025",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
image: "/images/img15.webp",
|
||||
category: "Insight",
|
||||
title: "FIREFIGHTING EQUIPMENT: TOOLS OF THE TRADE",
|
||||
author: "John Doe",
|
||||
date: "July 24, 2025",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
image: "/images/img16.webp",
|
||||
category: "News",
|
||||
title: "FIREFIGHTER TRAINING TAKES TO BECOME A HERO",
|
||||
author: "John Doe",
|
||||
date: "July 24, 2025",
|
||||
},
|
||||
];
|
||||
import { useTranslations } from "next-intl";
|
||||
import ProductCard from "../products/productCard";
|
||||
|
||||
export function Blog() {
|
||||
const t = useTranslations();
|
||||
const blogPosts = [
|
||||
{
|
||||
id: 1,
|
||||
image: "/images/img14.webp",
|
||||
category: "Tips & Trick",
|
||||
title: t("home.blog.articles.article1"),
|
||||
author: "John Doe",
|
||||
date: "July 24, 2025",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
image: "/images/img15.webp",
|
||||
category: "Insight",
|
||||
title: t("home.blog.articles.article2"),
|
||||
author: "John Doe",
|
||||
date: "July 24, 2025",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
image: "/images/img16.webp",
|
||||
category: "News",
|
||||
title: t("home.blog.articles.article3"),
|
||||
author: "John Doe",
|
||||
date: "July 24, 2025",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="bg-[#1f1f1f] py-45">
|
||||
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
@@ -37,23 +40,23 @@ export function Blog() {
|
||||
<div className="mb-12 text-center">
|
||||
<div className="mb-4 flex items-center justify-center gap-2">
|
||||
<DotAnimatsiya />
|
||||
<span className="text-sm font-semibold tracking-wider text-white uppercase">
|
||||
Blog & Articles
|
||||
<span className="font-almarai text-sm font-semibold tracking-wider text-white uppercase">
|
||||
{t("products.banner.title")}
|
||||
</span>
|
||||
</div>
|
||||
<h2
|
||||
className="bg-linear-to-br from-white via-white to-black
|
||||
className="font-unbounded bg-linear-to-br from-white py-2 via-white to-black
|
||||
text-transparent bg-clip-text text-4xl font-bold tracking-tight md:text-5xl lg:text-6xl"
|
||||
>
|
||||
LATEST BLOG & NEWS
|
||||
{t("products.ourproducts")}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
{/* Blog Cards Grid */}
|
||||
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3 max-sm:place-items-center">
|
||||
{blogPosts.map((post) => (
|
||||
{/* {blogPosts.map((post) => (
|
||||
<article key={post.id} className="group">
|
||||
{/* Image Container */}
|
||||
|
||||
<div className="relative mb-6 aspect-4/2 md:aspect-4/3 overflow-hidden rounded-lg">
|
||||
<Image
|
||||
src={post.image || "/placeholder.svg"}
|
||||
@@ -61,20 +64,19 @@ export function Blog() {
|
||||
fill
|
||||
className="object-cover transition-transform duration-300 group-hover:scale-105"
|
||||
/>
|
||||
{/* Category Badge */}
|
||||
|
||||
<div className="absolute bottom-4 left-4">
|
||||
<span className="rounded bg-red-600 px-4 py-2 text-sm font-medium text-white">
|
||||
<span className="font-almarai rounded bg-red-600 px-4 py-2 text-sm font-medium text-white">
|
||||
{post.category}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div>
|
||||
<h3 className="mb-3 text-lg font-bold leading-tight tracking-wide text-white uppercase md:text-xl">
|
||||
<h3 className="font-unbounded uppercase mb-3 text-lg font-bold leading-tight tracking-wide text-white md:text-xl">
|
||||
{post.title}
|
||||
</h3>
|
||||
<p className="mb-4 text-sm text-gray-400">
|
||||
<p className="font-almarai mb-4 text-sm text-gray-400">
|
||||
<span className="text-gray-500">by </span>
|
||||
<span className="text-white">{post.author}</span>
|
||||
<span className="mx-2 text-gray-500">•</span>
|
||||
@@ -82,14 +84,26 @@ export function Blog() {
|
||||
</p>
|
||||
<a
|
||||
href="#"
|
||||
className="inline-flex items-center gap-1 text-sm font-semibold tracking-wider text-red-600 uppercase transition-colors hover:text-red-500"
|
||||
className="font-almarai inline-flex items-center gap-1 text-sm font-semibold tracking-wider text-red-600 uppercase transition-colors hover:text-red-500"
|
||||
>
|
||||
Read More
|
||||
{t("home.blog.readMore")}
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</a>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
))} */}
|
||||
{Array(3)
|
||||
.fill(null)
|
||||
.map((_, index) => (
|
||||
<ProductCard
|
||||
key={index}
|
||||
title="Elektr yong'in detektori-Ypres ver.2"
|
||||
name="P-0834404"
|
||||
image="/images/products/products.webp"
|
||||
slug="P_0834404"
|
||||
status="full"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { Phone } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Image from "next/image";
|
||||
|
||||
export function Line() {
|
||||
const t = useTranslations();
|
||||
return (
|
||||
<div className="bg-black py-10 px-4">
|
||||
<div className="max-w-280 w-full mx-auto relative py-10 flex items-center justify-between ">
|
||||
<div className="text-white flex flex-col items-start justify-start gap-5 ">
|
||||
<h2 className="lg:text-5xl sm:text-3xl text-2xl max-w-[80%] w-full font-semibold">
|
||||
Ready for Action 24/7: Contact Us at
|
||||
<h2 className="font-almarai lg:text-5xl sm:text-3xl text-2xl max-w-[80%] w-full font-semibold">
|
||||
{t("home.contactLine.text")}
|
||||
</h2>
|
||||
<p className="flex items-center justify-center gap-4 font-semibold sm:text-xl text-lg">
|
||||
<span
|
||||
|
||||
@@ -1,63 +1,64 @@
|
||||
import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
|
||||
import { ChevronRight } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
export function OurService() {
|
||||
const t = useTranslations();
|
||||
return (
|
||||
<div className="bg-[#1e1d1c] py-10 md:py-16 lg:py-20">
|
||||
<div className="bg-[#1e1d1c] py-10 md:py-16 lg:py-20 mb-30">
|
||||
<div className="max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8">
|
||||
{/* Header */}
|
||||
<div className="space-y-4 md:space-y-6">
|
||||
<div className="flex items-center justify-center gap-2 text-base sm:text-lg md:text-xl text-white font-bold">
|
||||
<div className="font-almarai flex items-center justify-center gap-2 text-base sm:text-lg md:text-xl text-white font-bold">
|
||||
<DotAnimatsiya />
|
||||
OUR SERVICES
|
||||
{t("home.services.title")}
|
||||
</div>
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl xl:text-6xl tracking-wider lg:tracking-[5px] font-bold bg-linear-to-br from-white via-white to-gray-400 text-transparent bg-clip-text text-center w-full">
|
||||
FIREFIGHTER RESPONSIBILITIES
|
||||
<h1 className="uppercase font-unbounded text-2xl sm:text-3xl md:text-4xl lg:text-5xl xl:text-6xl tracking-wider lg:tracking-[5px] font-bold bg-linear-to-br from-white via-white to-gray-400 text-transparent bg-clip-text text-center w-full">
|
||||
{t("home.services.subtitle")}
|
||||
</h1>
|
||||
<p className="text-center text-sm sm:text-base md:text-lg text-gray-400 max-w-3xl mx-auto px-4">
|
||||
Aliquam lorem ante dapibus in viverra quis feugiat a tellus
|
||||
phasellus viverra nulla ut metus varius laoreet quisque rutrum.
|
||||
<p className="font-almarai text-center text-sm sm:text-base md:text-lg text-gray-400 max-w-4xl mx-auto px-4">
|
||||
{t("home.services.description")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* cards */}
|
||||
<div className="max-w-250 w-full mx-auto flex sm:flex-row flex-col items-center gap-5 my-10">
|
||||
<div className="relative space-y-4 py-6 px-8 rounded-xl sm:w-[55%] w-full bg-[linear-gradient(to_bottom_right,#000000,#000000,#000000,#d2610a)]">
|
||||
<p className="font-bold bg-linear-to-br from-white via-white to-black text-transparent bg-clip-text">
|
||||
Operation Force
|
||||
<p className="uppercase font-unbounded font-bold bg-linear-to-br from-white via-white to-black text-transparent bg-clip-text">
|
||||
{t("home.services.services.operation.title")}
|
||||
</p>
|
||||
<p className="text-gray-400 max-w-80 w-full">
|
||||
Aliquam lorem ante dapibus in viverra feugiat phasellus.
|
||||
<p className="font-almarai text-gray-400 max-w-80 w-full">
|
||||
{t("home.services.services.operation.description")}
|
||||
</p>
|
||||
<button className="text-[#dc2626] font-semibold flex items-center gap-2 text-sm">
|
||||
LEARN MORE <ChevronRight size={20} />
|
||||
<button className="font-almarai text-[#dc2626] font-semibold flex items-center gap-2 text-sm">
|
||||
{t("home.services.learnmore")} <ChevronRight size={20} />
|
||||
</button>
|
||||
<Image
|
||||
src="/images/home/gruop.png"
|
||||
alt="images"
|
||||
width={200}
|
||||
height={100}
|
||||
className="object-contain sm:absolute bottom-0 right-2 z-50"
|
||||
className="object-contain sm:absolute bottom-0 right-2 z-10"
|
||||
/>
|
||||
</div>
|
||||
<div className="relative overflow-hidden space-y-4 py-6 px-8 rounded-xl sm:w-[45%] w-full bg-[linear-gradient(to_bottom_right,#000000,#000000,#000000,#d2610a)]">
|
||||
<p className="font-bold bg-linear-to-br from-white via-white to-black text-transparent bg-clip-text">
|
||||
Operation Force
|
||||
<p className="uppercase font-unbounded font-bold bg-linear-to-br from-white via-white to-black text-transparent bg-clip-text">
|
||||
{t("home.services.services.suppression.title")}
|
||||
</p>
|
||||
<p className="text-gray-400 max-w-70 w-full">
|
||||
Aliquam lorem ante dapibus in viverra feugiat phasellus.
|
||||
<p className="font-almarai text-gray-400 max-w-70 w-full">
|
||||
{t("home.services.services.suppression.description")}
|
||||
</p>
|
||||
<button className="text-[#dc2626] font-semibold flex items-center gap-2 text-sm">
|
||||
LEARN MORE <ChevronRight size={20} />
|
||||
<button className="font-almarai text-[#dc2626] font-semibold flex items-center gap-2 text-sm">
|
||||
{t("home.services.learnmore")} <ChevronRight size={20} />
|
||||
</button>
|
||||
<Image
|
||||
src="/images/home/redShlang.png"
|
||||
alt="images"
|
||||
width={200}
|
||||
height={100}
|
||||
className="object-contain sm:absolute -bottom-4 -right-4 z-50"
|
||||
className="object-contain sm:absolute -bottom-4 -right-4 z-10"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -72,45 +73,45 @@ export function OurService() {
|
||||
className="object-contain mt-5"
|
||||
/>
|
||||
<div className="space-y-4 py-6 px-8">
|
||||
<p className="font-bold bg-linear-to-br from-white via-white to-black text-transparent bg-clip-text">
|
||||
Operation Force
|
||||
<p className="uppercase font-unbounded font-bold bg-linear-to-br from-white via-white to-black text-transparent bg-clip-text">
|
||||
{t("home.services.services.safety.title")}
|
||||
</p>
|
||||
<p className="text-gray-400 max-w-80 w-full">
|
||||
Aliquam lorem ante dapibus in viverra feugiat phasellus.
|
||||
<p className="font-almarai text-gray-400 max-w-80 w-full">
|
||||
{t("home.services.services.safety.description")}
|
||||
</p>
|
||||
<button className="text-[#dc2626] font-semibold flex items-center gap-2 text-sm">
|
||||
LEARN MORE <ChevronRight size={20} />
|
||||
<button className="font-almarai text-[#dc2626] font-semibold flex items-center gap-2 text-sm">
|
||||
{t("home.services.learnmore")} <ChevronRight size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sm:w-[60%] w-full">
|
||||
<div className="relative overflow-hidden space-y-4 py-6 px-8 rounded-xl w-full bg-[linear-gradient(to_bottom_right,#000000,#000000,#000000,#d2610a)]">
|
||||
<p className="font-bold bg-linear-to-br from-white via-white to-black text-transparent bg-clip-text">
|
||||
Operation Force
|
||||
<p className="uppercase font-unbounded font-bold bg-linear-to-br from-white via-white to-black text-transparent bg-clip-text">
|
||||
{t("home.services.services.monitoring.title")}
|
||||
</p>
|
||||
<p className="text-gray-400 max-w-70 w-full">
|
||||
Aliquam lorem ante dapibus in viverra feugiat phasellus.
|
||||
<p className="font-almarai text-gray-400 max-w-70 w-full">
|
||||
{t("home.services.services.monitoring.description")}
|
||||
</p>
|
||||
<button className="sm:mt-38 mt-0 text-[#dc2626] font-semibold flex items-center gap-2 text-sm">
|
||||
LEARN MORE <ChevronRight size={20} />
|
||||
<button className="font-almarai sm:mt-38 mt-0 text-[#dc2626] font-semibold flex items-center gap-2 text-sm">
|
||||
{t("home.services.learnmore")} <ChevronRight size={20} />
|
||||
</button>
|
||||
<Image
|
||||
src="/images/home/balon.png"
|
||||
alt="images"
|
||||
width={200}
|
||||
height={100}
|
||||
className="object-contain sm:absolute -bottom-20 -right-4 max-sm:-mb-20 z-50"
|
||||
className="object-contain sm:absolute -bottom-20 -right-4 max-sm:-mb-20 z-10"
|
||||
/>
|
||||
</div>
|
||||
<div className="py-8 px-8 rounded-xl mt-5 w-full p-5 bg-[linear-gradient(to_top_right,#000000,#000000,#d2610a)] flex sm:flex-row flex-col gap-5 items-center justify-between">
|
||||
<h2 className="sm:text-3xl text-xl font-semibold font-armanai text-white">
|
||||
View more service
|
||||
<h2 className="font-unbounded sm:text-3xl text-xl font-semibold font-armanai text-white">
|
||||
{t("home.services.viewMoreServices")}
|
||||
</h2>
|
||||
<Link
|
||||
href="/services"
|
||||
className="shadow-[0px_0px_2px_6px_#a60404ad] bg-red-600 hover:bg-red-700 text-white font-bold sm:py-3 sm:px-8 px-8 py-2 rounded-full transition duration-300 transform hover:scale-105 w-fit"
|
||||
className="font-almarai shadow-[0px_0px_2px_6px_#a60404ad] bg-red-600 hover:bg-red-700 text-white font-bold sm:py-3 sm:px-8 px-8 py-2 rounded-full transition duration-300 transform hover:scale-105 w-fit"
|
||||
>
|
||||
GET STARTED
|
||||
{t("home.services.viewMore")}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
import { Counter } from "@/components/Counter";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export function Statistics() {
|
||||
const t = useTranslations();
|
||||
const stats = [
|
||||
{
|
||||
number: '25',
|
||||
symbol: '+',
|
||||
label: 'Years Experience',
|
||||
number: "25",
|
||||
symbol: "+",
|
||||
label: t("home.statistics.experience"),
|
||||
},
|
||||
{
|
||||
number: '450',
|
||||
symbol: '+',
|
||||
label: 'Families Saved',
|
||||
number: "450",
|
||||
symbol: "+",
|
||||
label: t("home.statistics.projectsCompleted"),
|
||||
},
|
||||
{
|
||||
number: '99',
|
||||
symbol: '+',
|
||||
label: 'Trained Staff',
|
||||
number: "99",
|
||||
symbol: "+",
|
||||
label: t("home.statistics.trainedSpecialists"),
|
||||
},
|
||||
{
|
||||
number: '93',
|
||||
symbol: '%',
|
||||
label: 'Trusted Clients',
|
||||
number: "93",
|
||||
symbol: "%",
|
||||
label: t("home.statistics.trustedClients"),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -27,17 +31,22 @@ export function Statistics() {
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 lg:gap-12">
|
||||
{stats.map((stat, index) => (
|
||||
<div key={index} className="flex flex-col items-center justify-center py-10 sm:py-20 lg:py-15 border-b-red-600 border-b">
|
||||
<div
|
||||
key={index}
|
||||
className="flex flex-col items-center justify-center py-10 sm:py-20 lg:py-15 border-b-red-600 border-b"
|
||||
>
|
||||
{/* Number and Symbol */}
|
||||
<div className="flex items-baseline gap-2">
|
||||
<div className="flex items-baseline gap-2 font-almarai">
|
||||
<span className="text-4xl sm:text-5xl lg:text-6xl font-bold text-white">
|
||||
{stat.number}
|
||||
<Counter countNum={Number(stat.number)} />
|
||||
</span>
|
||||
<span className="text-4xl sm:text-5xl lg:text-6xl font-bold text-red-600">
|
||||
{stat.symbol}
|
||||
</span>
|
||||
<span className="text-4xl sm:text-5xl lg:text-6xl font-bold text-red-600">{stat.symbol}</span>
|
||||
</div>
|
||||
|
||||
{/* Label */}
|
||||
<p className="text-sm sm:text-base text-gray-300 mt-4 text-center font-medium">
|
||||
<p className="font-almarai text-sm sm:text-base text-gray-300 mt-4 text-center font-medium">
|
||||
{stat.label}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -5,36 +5,7 @@ import { Autoplay } from "swiper/modules";
|
||||
import Image from "next/image";
|
||||
import "swiper/css";
|
||||
import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
|
||||
|
||||
const testimonials = [
|
||||
{
|
||||
id: 1,
|
||||
quote:
|
||||
"I've witnessed Fireforce in action multiple times, and they never cease to amaze me with their dedication and professionalism. They are the backbone of our safety and security. Thank you, Fireforce!",
|
||||
name: "JOHN SMITH",
|
||||
role: "Manager",
|
||||
avatar: "/images/home/avatar.jpg",
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
quote:
|
||||
"The team's response time and expertise saved our property from a devastating fire. Their bravery and commitment to protecting our community is truly remarkable. Highly recommend their services!",
|
||||
name: "SARAH JOHNSON",
|
||||
role: "Business Owner",
|
||||
avatar: "/images/home/avatar.jpg",
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
quote:
|
||||
"Working alongside Fireforce has been an honor. Their training programs and emergency protocols are second to none. They set the standard for fire safety excellence in our region.",
|
||||
name: "MICHAEL DAVIS",
|
||||
role: "Safety Director",
|
||||
avatar: "/images/home/avatar.jpg",
|
||||
rating: 5,
|
||||
},
|
||||
];
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
function StarRating({ rating }: { rating: number }) {
|
||||
return (
|
||||
@@ -53,6 +24,33 @@ function StarRating({ rating }: { rating: number }) {
|
||||
}
|
||||
|
||||
export function Testimonial() {
|
||||
const t = useTranslations();
|
||||
const testimonials = [
|
||||
{
|
||||
id: 1,
|
||||
quote:t("home.testimonials.clients.john.text"),
|
||||
name: t("home.testimonials.clients.john.name"),
|
||||
role: t("home.testimonials.clients.john.position"),
|
||||
avatar: "/images/home/avatar.jpg",
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
quote:t("home.testimonials.clients.sarah.text"),
|
||||
name: t("home.testimonials.clients.sarah.name"),
|
||||
role: t("home.testimonials.clients.sarah.position"),
|
||||
avatar: "/images/home/avatar.jpg",
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
quote:t("home.testimonials.clients.michael.text"),
|
||||
name: t("home.testimonials.clients.michael.name"),
|
||||
role: t("home.testimonials.clients.michael.position"),
|
||||
avatar: "/images/home/avatar.jpg",
|
||||
rating: 5,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<section className="w-full bg-[#1a1a1a]">
|
||||
<div className="flex flex-col lg:flex-row min-h-100 lg:min-h-125">
|
||||
@@ -87,8 +85,8 @@ export function Testimonial() {
|
||||
<div className="w-full max-w-xl mx-auto mb-5">
|
||||
<div className="flex items-center gap-2">
|
||||
<DotAnimatsiya />
|
||||
<span className="text-white font-semibold text-sm tracking-wider">
|
||||
TESTIMONIALS
|
||||
<span className="font-unbounded text-white font-semibold text-sm tracking-wider">
|
||||
{t("home.testimonials.title")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -108,7 +106,7 @@ export function Testimonial() {
|
||||
<SwiperSlide key={testimonial.id}>
|
||||
<div className="space-y-6">
|
||||
{/* Quote */}
|
||||
<p className="text-white text-base sm:text-lg lg:text-xl leading-relaxed">
|
||||
<p className="font-almarai text-white text-base sm:text-lg lg:text-xl leading-relaxed">
|
||||
"{testimonial.quote}"
|
||||
</p>
|
||||
|
||||
@@ -123,10 +121,10 @@ export function Testimonial() {
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-white font-bold text-sm sm:text-base">
|
||||
<h4 className="font-unbounded text-white font-bold text-sm sm:text-base">
|
||||
{testimonial.name}
|
||||
</h4>
|
||||
<p className="text-red-600 text-xs sm:text-sm">
|
||||
<p className="font-almarai text-red-600 text-xs sm:text-sm">
|
||||
{testimonial.role}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,15 +1,27 @@
|
||||
import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
|
||||
import HomeMarquee from "@/components/HomeMarquee";
|
||||
import { Play } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export function Video() {
|
||||
const t = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="bg-[#1e1d1c] bg-fixed max-sm:bg-center"
|
||||
style={{ backgroundImage: "url(/images/img7.jpg)" }}
|
||||
>
|
||||
<div className="flex items-center justify-center bg-linear-to-t from-[#1e1d1c] to-[#1e1d1c02] h-80 w-full relative">
|
||||
|
||||
<div className="flex flex-col items-center justify-center bg-linear-to-t from-[#1e1d1c] to-[#1e1d1c02] h-80 w-full relative">
|
||||
<div className="flex items-center gap-2 w-fit text-white ">
|
||||
<DotAnimatsiya />
|
||||
<span className="text-sm font-semibold tracking-wide font-almarai">
|
||||
{t("rasmlar")}
|
||||
</span>
|
||||
</div>
|
||||
<h1 className="font-unbounded uppercase text-4xl bg-linear-to-br from-white via-white to-black
|
||||
text-transparent bg-clip-text sm:text-5xl lg:text-6xl font-bold leading-tight text-pretty">
|
||||
{t("fotogalereya")}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export function ProductBanner() {
|
||||
const t = useTranslations();
|
||||
return (
|
||||
<section className="relative w-full h-[60vh] min-h-100 overflow-hidden pt-10">
|
||||
{/* Background Image */}
|
||||
@@ -24,17 +26,21 @@ export function ProductBanner() {
|
||||
<div className="max-w-250 w-full mx-auto px-4">
|
||||
<div className="relative z-20 h-full flex max-lg:flex-col items-start justify-between gap-5 pt-30">
|
||||
<div className="spacw-y-4 ">
|
||||
<DotAnimatsiya />
|
||||
<div className="flex items-center gap-2 w-fit">
|
||||
<DotAnimatsiya />
|
||||
<span className="font-almarai text-white text-sm font-semibold tracking-wide">
|
||||
{t("products.banner.title")}
|
||||
</span>
|
||||
</div>
|
||||
<p
|
||||
className=" bg-linear-to-br from-white via-white to-black
|
||||
text-transparent bg-clip-text text-4xl sm:text-5xl lg:text-6xl font-bold leading-tight text-pretty"
|
||||
className="font-unbounded uppercase bg-linear-to-br from-white via-white to-black
|
||||
text-transparent bg-clip-text text-3xl sm:text-4xl lg:text-5xl font-bold leading-tight text-pretty"
|
||||
>
|
||||
Ignum technology <br /> At The Ready
|
||||
{t("products.banner.subtitle")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="lg:w-[40%] text-gray-300 lg:mt-20 md:mt-10 sm:mt-5 ">
|
||||
It emphasizes that these firefighters are there not just as public
|
||||
servants but as a vital part of the community.
|
||||
<div className="font-almarai lg:w-[40%] text-gray-300 lg:mt-20 md:mt-10 sm:mt-5 ">
|
||||
{t("products.banner.description")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function ProductCard({
|
||||
<Link href={`/products/${slug}`}>
|
||||
<article className="group transition-all duration-300 hover:cursor-pointer max-sm:max-w-100 max-sm:mx-auto max-sm:w-full ">
|
||||
{/* Image Container */}
|
||||
<div className="relative rounded-2xl h-45 sm:h-55 md:h-65 lg:w-70 w-[90%] mx-auto overflow-hidden bg-white">
|
||||
<div className="relative rounded-2xl h-45 sm:h-55 md:h-65 lg:w-[95%] w-[90%] mx-auto overflow-hidden bg-white">
|
||||
<Image
|
||||
src={image || "/placeholder.svg"}
|
||||
alt={title}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export function ServiceBanner() {
|
||||
const t = useTranslations();
|
||||
return (
|
||||
<section className="relative w-full h-[60vh] min-h-100 overflow-hidden pt-10">
|
||||
{/* Background Image */}
|
||||
@@ -24,17 +26,21 @@ export function ServiceBanner() {
|
||||
<div className="max-w-250 w-full mx-auto px-4">
|
||||
<div className="relative z-20 h-full flex max-lg:flex-col items-start justify-between gap-5 pt-30">
|
||||
<div className="spacw-y-4 ">
|
||||
<DotAnimatsiya />
|
||||
<div className="flex items-center gap-3">
|
||||
<DotAnimatsiya />
|
||||
<span className="font-almarai text-sm text-white font-semibold tracking-wide">
|
||||
{t("services.banner.title")}
|
||||
</span>
|
||||
</div>
|
||||
<p
|
||||
className=" bg-linear-to-br from-white via-white to-black
|
||||
className="font-unbounded uppercase bg-linear-to-br from-white via-white to-black
|
||||
text-transparent bg-clip-text text-4xl sm:text-5xl lg:text-6xl font-bold leading-tight text-pretty"
|
||||
>
|
||||
GENERAL <br /> QUESTIONS
|
||||
{t("services.banner.subtitle")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="lg:w-[40%] text-gray-300 mt-10 text-lg">
|
||||
Always Ready, Always On Time: Rescuing Lives” represents an
|
||||
unwavering commitment to emergency.
|
||||
<div className="font-almarai lg:w-[40%] text-gray-300 mt-10 text-lg">
|
||||
{t("services.banner.description")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,36 @@
|
||||
import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
|
||||
import FAQAccordion from "../faq/faqAccardion";
|
||||
import { faqItems } from "@/lib/demoData";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export function ServiceFaq() {
|
||||
const t = useTranslations();
|
||||
const faqItems = [
|
||||
{
|
||||
id: "faq-1",
|
||||
question: t("faq.question1.question"),
|
||||
answer: t("faq.question1.answer"),
|
||||
},
|
||||
{
|
||||
id: "faq-2",
|
||||
question: t("faq.question2.question"),
|
||||
answer: t("faq.question2.answer"),
|
||||
},
|
||||
{
|
||||
id: "faq-3",
|
||||
question: t("faq.question3.question"),
|
||||
answer: t("faq.question3.answer"),
|
||||
},
|
||||
{
|
||||
id: "faq-4",
|
||||
question: t("faq.question4.question"),
|
||||
answer: t("faq.question4.answer"),
|
||||
},
|
||||
{
|
||||
id: "faq-5",
|
||||
question: t("faq.question5.question"),
|
||||
answer: t("faq.question5.answer"),
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div className="bg-[#1e1d1c] py-20 pb-50 space-y-8">
|
||||
{/* header */}
|
||||
|
||||
16
i18n/config.ts
Normal file
16
i18n/config.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export const locales = ["uz", "ru", "en"] as const
|
||||
export type Locale = (typeof locales)[number]
|
||||
|
||||
export const defaultLocale: Locale = "uz"
|
||||
|
||||
export const localeNames: Record<Locale, string> = {
|
||||
uz: "O'zbekcha",
|
||||
ru: "Русский",
|
||||
en: "English",
|
||||
}
|
||||
|
||||
export const localeFlags: Record<Locale, string> = {
|
||||
uz: "🇺🇿",
|
||||
ru: "🇷🇺",
|
||||
en: "🇬🇧",
|
||||
}
|
||||
25
i18n/request.ts
Normal file
25
i18n/request.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// i18n/request.ts
|
||||
import { getRequestConfig } from 'next-intl/server';
|
||||
import { headers } from 'next/headers';
|
||||
|
||||
const LOCALES = ["uz", "ru", "en"] as const;
|
||||
const DEFAULT_LOCALE = "uz";
|
||||
|
||||
type Locale = typeof LOCALES[number];
|
||||
|
||||
export default getRequestConfig(async () => {
|
||||
const headersList = await headers();
|
||||
|
||||
// ✅ Middleware allaqachon locale'ni set qilgan
|
||||
const locale = headersList.get('x-locale') || DEFAULT_LOCALE;
|
||||
|
||||
// Validate
|
||||
const validLocale = LOCALES.includes(locale as Locale)
|
||||
? locale
|
||||
: DEFAULT_LOCALE;
|
||||
|
||||
return {
|
||||
locale: validLocale,
|
||||
messages: (await import(`../messages/${validLocale}.json`)).default,
|
||||
};
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
export const DATA = [
|
||||
{
|
||||
name: "P-0834405",
|
||||
|
||||
23
lib/i18n-utils.ts
Normal file
23
lib/i18n-utils.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
"use client"
|
||||
|
||||
import { Locale } from "@/i18n/config"
|
||||
import { useRouter } from "next/navigation"
|
||||
|
||||
export function useChangeLocale() {
|
||||
const router = useRouter()
|
||||
|
||||
const changeLocale = (locale: Locale) => {
|
||||
document.cookie = `NEXT_LOCALE=${locale}; path=/; max-age=31536000`
|
||||
router.refresh()
|
||||
}
|
||||
|
||||
return changeLocale
|
||||
}
|
||||
|
||||
export function getLocaleFromCookie(): Locale {
|
||||
if (typeof document === "undefined") return "uz"
|
||||
|
||||
const cookie = document.cookie.split("; ").find((row) => row.startsWith("NEXT_LOCALE="))
|
||||
|
||||
return (cookie?.split("=")[1] as Locale) || "uz"
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"home": {
|
||||
"banner": {
|
||||
"title1": "Welcome to Ignum",
|
||||
"title2": "Fire Protection Guardian",
|
||||
"title2": "FIRE PROTECTION GUARDIAN",
|
||||
"description": "We are seen as a beacon of hope, a figure that brings calm amidst chaos and light in the darkest of moments.",
|
||||
"cta": "Get Started"
|
||||
},
|
||||
@@ -150,7 +150,8 @@
|
||||
"title": "Products",
|
||||
"subtitle": "Ignum Technology Ready",
|
||||
"description": "We not only supply equipment but become a successful partner for every client."
|
||||
}
|
||||
},
|
||||
"ourproducts": "Our Products"
|
||||
},
|
||||
"faq": {
|
||||
"banner": {
|
||||
@@ -158,28 +159,31 @@
|
||||
"subtitle": "General Questions",
|
||||
"topic": "ABOUT WORK"
|
||||
},
|
||||
"questions": [
|
||||
{
|
||||
"question": "How to choose a fire alarm system?",
|
||||
"answer": "Depending on the area, type and features of the facility, our specialists will offer you the most optimal solution. You can get a free consultation."
|
||||
},
|
||||
{
|
||||
"question": "How long does equipment installation take?",
|
||||
"answer": "Installation time depends on the project scope. Usually, 1-3 days for small facilities, 1-2 weeks for large facilities."
|
||||
},
|
||||
{
|
||||
"question": "How is maintenance carried out?",
|
||||
"answer": "We offer regular maintenance and 24/7 emergency service. Preventive inspections are conducted every six months."
|
||||
},
|
||||
{
|
||||
"question": "What is the warranty period?",
|
||||
"answer": "All our equipment comes with a 2-year warranty and 10-year maintenance guarantee."
|
||||
},
|
||||
{
|
||||
"question": "For which facilities are they suitable?",
|
||||
"answer": "We have suitable solutions for office buildings, warehouses, industrial plants, shopping malls, residential buildings and all types of public places."
|
||||
}
|
||||
]
|
||||
"question1": {
|
||||
"question": "How to choose a fire alarm system?",
|
||||
"answer": "Depending on the area, type and features of the facility, our specialists will offer you the most optimal solution. You can get a free consultation."
|
||||
},
|
||||
"question2": {
|
||||
"question": "How long does equipment installation take?",
|
||||
"answer": "Installation time depends on the project scope. Usually, 1-3 days for small facilities, 1-2 weeks for large facilities."
|
||||
},
|
||||
"question3": {
|
||||
"question": "How is maintenance carried out?",
|
||||
"answer": "We offer regular maintenance and 24/7 emergency service. Preventive inspections are conducted every six months."
|
||||
},
|
||||
"question4": {
|
||||
"question": "What is the warranty period?",
|
||||
"answer": "All our equipment comes with a 2-year warranty and 10-year maintenance guarantee."
|
||||
},
|
||||
"question5": {
|
||||
"question": "For which facilities are they suitable?",
|
||||
"answer": "We have suitable solutions for office buildings, warehouses, industrial plants, shopping malls, residential buildings and all types of public places."
|
||||
},
|
||||
"ask": {
|
||||
"question": "Do you still have questions?",
|
||||
"subtitle": "Contact us and our specialists will answer you",
|
||||
"btn": "Ask Question"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"banner": {
|
||||
@@ -213,5 +217,11 @@
|
||||
"contact": "Contact",
|
||||
"help": "Help"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"rasmlar": "Images",
|
||||
"fotogalereya": "Photo Gallery",
|
||||
"contactTitle": "Send us your phone number",
|
||||
"contactSubTitle": "Our staff will contact you",
|
||||
"enterPhone": "Enter your phone number",
|
||||
"send": "Send"
|
||||
}
|
||||
@@ -150,7 +150,8 @@
|
||||
"title": "Продукты",
|
||||
"subtitle": "Технология Ignum Готова",
|
||||
"description": "Мы не просто поставляем оборудование, мы становимся успешным партнером для каждого клиента."
|
||||
}
|
||||
},
|
||||
"ourproducts": "Наши продукты"
|
||||
},
|
||||
"faq": {
|
||||
"banner": {
|
||||
@@ -158,28 +159,31 @@
|
||||
"subtitle": "Общие Вопросы",
|
||||
"topic": "О РАБОТЕ"
|
||||
},
|
||||
"questions": [
|
||||
{
|
||||
"question": "Как выбрать систему пожарной сигнализации?",
|
||||
"answer": "В зависимости от площади, типа и особенностей объекта наши специалисты предложат вам наиболее оптимальное решение. Вы можете получить бесплатную консультацию."
|
||||
},
|
||||
{
|
||||
"question": "Сколько времени занимает установка оборудования?",
|
||||
"answer": "Время установки зависит от объема проекта. Обычно для небольших объектов требуется 1-3 дня, для крупных объектов - 1-2 недели."
|
||||
},
|
||||
{
|
||||
"question": "Как проводится техническое обслуживание?",
|
||||
"answer": "Мы предлагаем регулярное техническое обслуживание и экстренную службу 24/7. Профилактические проверки проводятся каждые шесть месяцев."
|
||||
},
|
||||
{
|
||||
"question": "Какой срок гарантии?",
|
||||
"answer": "На все наше оборудование предоставляется 2-летняя гарантия и 10-летняя гарантия на техническое обслуживание."
|
||||
},
|
||||
{
|
||||
"question": "Для каких объектов подходят?",
|
||||
"answer": "У нас есть подходящие решения для офисных зданий, складов, промышленных предприятий, торговых центров, жилых зданий и всех видов общественных мест."
|
||||
}
|
||||
]
|
||||
"question1": {
|
||||
"question": "Как выбрать систему пожарной сигнализации?",
|
||||
"answer": "В зависимости от площади, типа и особенностей объекта наши специалисты предложат вам наиболее оптимальное решение. Вы можете получить бесплатную консультацию."
|
||||
},
|
||||
"question2": {
|
||||
"question": "Сколько времени занимает установка оборудования?",
|
||||
"answer": "Время установки зависит от объема проекта. Обычно для небольших объектов требуется 1-3 дня, для крупных объектов - 1-2 недели."
|
||||
},
|
||||
"question3": {
|
||||
"question": "Как проводится техническое обслуживание?",
|
||||
"answer": "Мы предлагаем регулярное техническое обслуживание и экстренную службу 24/7. Профилактические проверки проводятся каждые шесть месяцев."
|
||||
},
|
||||
"question4": {
|
||||
"question": "Какой срок гарантии?",
|
||||
"answer": "На все наше оборудование предоставляется 2-летняя гарантия и 10-летняя гарантия на техническое обслуживание."
|
||||
},
|
||||
"question5": {
|
||||
"question": "Для каких объектов подходят?",
|
||||
"answer": "У нас есть подходящие решения для офисных зданий, складов, промышленных предприятий, торговых центров, жилых зданий и всех видов общественных мест."
|
||||
},
|
||||
"ask": {
|
||||
"question": "Остались вопросы?",
|
||||
"subtitle": "Свяжитесь с нами, и наши специалисты ответят вам",
|
||||
"btn": "Задать вопрос"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"banner": {
|
||||
@@ -213,5 +217,11 @@
|
||||
"contact": "Контакты",
|
||||
"help": "Помощь"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"rasmlar": "Изображения",
|
||||
"fotogalereya": "Фотогалерея",
|
||||
"contactTitle": "Отправьте нам свой номер",
|
||||
"contactSubTitle": "Наши сотрудники свяжутся с вами",
|
||||
"enterPhone": "Введите ваш номер телефона",
|
||||
"send": "Отправить"
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"home": {
|
||||
"banner": {
|
||||
"title1": "Ignum-ga xush kelibsiz",
|
||||
"title2": "Yong'inga Qarshi Himoya",
|
||||
"title2": "YONG'INGA QARSHI HIMOYA",
|
||||
"description": "Biz umid nuri, tartibsizlik davrida tinchlik va eng qiyin vaziyatlarda ishonchli himoya manbai sifatida ko'rilamiz.",
|
||||
"cta": "Boshlash"
|
||||
},
|
||||
@@ -14,17 +14,17 @@
|
||||
},
|
||||
"about": {
|
||||
"title": "Biz haqimizda",
|
||||
"subtitle": "Yong'inga Qarshi Tizimlar Tayyor",
|
||||
"subtitle": "YONG'INGA QARSHI TIZIMLAR TAYYOR",
|
||||
"prevention": {
|
||||
"title": "Yong'inni Oldini Olish Tizimlari",
|
||||
"title": "YONG'INDI OLDINI OLISH TIZIMLARI",
|
||||
"description": "Biz eng ilg'or yong'in oldini olish texnologiyalarini taklif etamiz. Har bir detal xavfsizlik va ishonchlilikni ta'minlash uchun ishlab chiqilgan."
|
||||
},
|
||||
"accidents": {
|
||||
"title": "Favqulodda Holatlar",
|
||||
"title": "FAVQULODDA HOLATLAR",
|
||||
"description": "Har qanday vaziyatga tezkor va samarali javob berish uchun mo'ljallangan avtomatik o'chirish tizimlari. Xavfsizlik - bizning birinchi ustuvorligimiz."
|
||||
},
|
||||
"service": {
|
||||
"title": "Texnik Xizmat",
|
||||
"title": "TEXNIK XIZMAT",
|
||||
"description": "Muntazam texnik xizmat ko'rsatish va ta'mirlash xizmatlari. Tizimlaringiz har doim ish holatida bo'lishini kafolatlaymiz."
|
||||
},
|
||||
"award": "Eng Yaxshi Yong'in Himoyasi 2025"
|
||||
@@ -53,7 +53,7 @@
|
||||
}
|
||||
},
|
||||
"viewMoreServices": "Ko'proq Xizmatlar",
|
||||
"viewMore": "Ko'proq"
|
||||
"viewMore": "Ko'proq ko'rish"
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Mijozlar Fikrlari",
|
||||
@@ -80,7 +80,7 @@
|
||||
},
|
||||
"blog": {
|
||||
"title": "Blog & Maqolalar",
|
||||
"subtitle": "SO'NGI BLOG & YANGILIKLAR",
|
||||
"subtitle": "BLOG & SO'NGI YANGILIKLAR",
|
||||
"articles": {
|
||||
"article1": "YONG'IN HIMOYASI TIZIMLARI: QANDAY ISHLAYDI?",
|
||||
"article2": "YANGI TEXNOLOGIYALAR: AQLLI O'CHIRISH TIZIMLARI",
|
||||
@@ -150,7 +150,8 @@
|
||||
"title": "Mahsulotlar",
|
||||
"subtitle": "Ignum Texnologiyasi Tayyor",
|
||||
"description": "Biz nafaqat uskunalar yetkazib beramiz, balki har bir mijozning muvaffaqiyatli hamkoriga aylanamiz."
|
||||
}
|
||||
},
|
||||
"ourproducts": "Bizning mahsulotlarimiz"
|
||||
},
|
||||
"faq": {
|
||||
"banner": {
|
||||
@@ -158,28 +159,31 @@
|
||||
"subtitle": "Umumiy Savollar",
|
||||
"topic": "ISH HAQIDA"
|
||||
},
|
||||
"questions": [
|
||||
{
|
||||
"question": "Yong'in signalizatsiya tizimini qanday tanlash kerak?",
|
||||
"answer": "Ob'ektning maydoni, turi va xususiyatlariga qarab mutaxassislarimiz sizga eng optimal yechimni taklif qiladilar. Bepul konsultatsiya olishingiz mumkin."
|
||||
},
|
||||
{
|
||||
"question": "Uskunalarni o'rnatish qancha vaqt oladi?",
|
||||
"answer": "O'rnatish vaqti loyiha hajmiga bog'liq. Odatda, kichik ob'ektlar uchun 1-3 kun, yirik ob'ektlar uchun 1-2 hafta kerak bo'ladi."
|
||||
},
|
||||
{
|
||||
"question": "Texnik xizmat ko'rsatish qanday amalga oshiriladi?",
|
||||
"answer": "Biz muntazam texnik xizmat ko'rsatish va 24/7 favqulodda xizmatni taklif etamiz. Har olti oyda bir marta profilaktik tekshiruvlar o'tkaziladi."
|
||||
},
|
||||
{
|
||||
"question": "Kafolatiy muddati qancha?",
|
||||
"answer": "Barcha uskunalarimiz uchun 2 yillik kafolat va 10 yillik texnik xizmat ko'rsatish kafolati beriladi."
|
||||
},
|
||||
{
|
||||
"question": "Qanday ob'ektlar uchun mos?",
|
||||
"answer": "Ofis binalari, omborxonalar, sanoat korxonalari, savdo markazlari, turar-joy binolari va barcha turdagi jamoat joylari uchun mos yechimlarimiz mavjud."
|
||||
}
|
||||
]
|
||||
"question1": {
|
||||
"question": "Yong'in signalizatsiya tizimini qanday tanlash kerak?",
|
||||
"answer": "Ob'ektning maydoni, turi va xususiyatlariga qarab mutaxassislarimiz sizga eng optimal yechimni taklif qiladilar. Bepul konsultatsiya olishingiz mumkin."
|
||||
},
|
||||
"question2": {
|
||||
"question": "Uskunalarni o'rnatish qancha vaqt oladi?",
|
||||
"answer": "O'rnatish vaqti loyiha hajmiga bog'liq. Odatda, kichik ob'ektlar uchun 1-3 kun, yirik ob'ektlar uchun 1-2 hafta kerak bo'ladi."
|
||||
},
|
||||
"question3": {
|
||||
"question": "Texnik xizmat ko'rsatish qanday amalga oshiriladi?",
|
||||
"answer": "Biz muntazam texnik xizmat ko'rsatish va 24/7 favqulodda xizmatni taklif etamiz. Har olti oyda bir marta profilaktik tekshiruvlar o'tkaziladi."
|
||||
},
|
||||
"question4": {
|
||||
"question": "Kafolatiy muddati qancha?",
|
||||
"answer": "Barcha uskunalarimiz uchun 2 yillik kafolat va 10 yillik texnik xizmat ko'rsatish kafolati beriladi."
|
||||
},
|
||||
"question5": {
|
||||
"question": "Qanday ob'ektlar uchun mos?",
|
||||
"answer": "Ofis binalari, omborxonalar, sanoat korxonalari, savdo markazlari, turar-joy binolari va barcha turdagi jamoat joylari uchun mos yechimlarimiz mavjud."
|
||||
},
|
||||
"ask": {
|
||||
"question": "Hali ham savolingiz bormi?",
|
||||
"subtitle": "Bizga bo'glaning va bizni hodilarimiz sizga javob berishadi",
|
||||
"btn": "Savollingizni yo'llang"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"banner": {
|
||||
@@ -213,5 +217,11 @@
|
||||
"contact": "Aloqa",
|
||||
"help": "Yordam"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"rasmlar": "Rasmlar",
|
||||
"fotogalereya": "Fotogalereya",
|
||||
"contactTitle": "Bizga raqamingizni yuboring",
|
||||
"contactSubTitle": "Xodimlarimiz siz bilan bog'lanishadi",
|
||||
"enterPhone":"Telefon raqamingiz kiriting",
|
||||
"send":"Yuborish"
|
||||
}
|
||||
136
middleware.ts
Normal file
136
middleware.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { match as matchLocale } from "@formatjs/intl-localematcher";
|
||||
import Negotiator from "negotiator";
|
||||
const PUBLIC_PAGES = ["/login", "/register"];
|
||||
|
||||
const LOCALES = ["uz", "ru", "en"];
|
||||
const DEFAULT_LOCALE = "uz";
|
||||
|
||||
type Locale = (typeof LOCALES)[number];
|
||||
|
||||
function getLocaleFromPathname(pathname: string): Locale | null {
|
||||
const segments = pathname.split("/").filter(Boolean);
|
||||
const firstSegment = segments[0];
|
||||
|
||||
if (firstSegment && LOCALES.includes(firstSegment as Locale)) {
|
||||
return firstSegment as Locale;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getLocaleFromCookie(request: NextRequest): Locale | null {
|
||||
const cookieLocale = request.cookies.get("NEXT_LOCALE")?.value;
|
||||
|
||||
if (cookieLocale && LOCALES.includes(cookieLocale as Locale)) {
|
||||
return cookieLocale as Locale;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getLocaleFromHeaders(request: NextRequest): Locale {
|
||||
const negotiatorHeaders: Record<string, string> = {};
|
||||
request.headers.forEach((value, key) => {
|
||||
negotiatorHeaders[key] = value;
|
||||
});
|
||||
|
||||
const languages = new Negotiator({ headers: negotiatorHeaders }).languages();
|
||||
|
||||
try {
|
||||
return matchLocale(
|
||||
languages,
|
||||
LOCALES as unknown as string[],
|
||||
DEFAULT_LOCALE
|
||||
) as Locale;
|
||||
} catch {
|
||||
return DEFAULT_LOCALE;
|
||||
}
|
||||
}
|
||||
|
||||
export function middleware(request: NextRequest) {
|
||||
const { pathname, search } = request.nextUrl;
|
||||
|
||||
// Skip public files and API routes
|
||||
if (
|
||||
pathname.includes(".") ||
|
||||
pathname.startsWith("/api") ||
|
||||
pathname.startsWith("/_next")
|
||||
) {
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
// 1. Check URL locale
|
||||
const localeFromPath = getLocaleFromPathname(pathname);
|
||||
|
||||
// 2. Check cookie locale
|
||||
const localeFromCookie = getLocaleFromCookie(request);
|
||||
|
||||
// 3. Check browser locale
|
||||
const localeFromBrowser = getLocaleFromHeaders(request);
|
||||
|
||||
// Priority: URL > Cookie > Browser
|
||||
const preferredLocale =
|
||||
localeFromPath || localeFromCookie || localeFromBrowser;
|
||||
|
||||
// Faqat kerakli sahifalarni redirect qilamiz
|
||||
const isPublicPage = PUBLIC_PAGES.some((page) => pathname === page);
|
||||
|
||||
if (isPublicPage) {
|
||||
const url = request.nextUrl.clone();
|
||||
url.pathname = `/${DEFAULT_LOCALE}/verify-otp`;
|
||||
url.search = search; // ?code=1111&phone=...
|
||||
|
||||
return NextResponse.redirect(url);
|
||||
}
|
||||
|
||||
// If URL has no locale, redirect with preferred locale
|
||||
if (!localeFromPath) {
|
||||
const newUrl = new URL(`/${preferredLocale}/${pathname}`, request.url);
|
||||
return NextResponse.redirect(newUrl);
|
||||
}
|
||||
|
||||
// If URL locale differs from cookie, update cookie
|
||||
if (localeFromPath !== localeFromCookie) {
|
||||
const response = NextResponse.next();
|
||||
|
||||
// ✅ Set cookie on server side
|
||||
response.cookies.set("NEXT_LOCALE", localeFromPath, {
|
||||
path: "/",
|
||||
maxAge: 31536000, // 1 year
|
||||
sameSite: "lax",
|
||||
});
|
||||
|
||||
// ✅ Pass locale to request headers for server components
|
||||
const requestHeaders = new Headers(request.headers);
|
||||
requestHeaders.set("x-locale", localeFromPath);
|
||||
requestHeaders.set("x-pathname", pathname);
|
||||
|
||||
return NextResponse.next({
|
||||
request: {
|
||||
headers: requestHeaders,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Normal flow - just pass locale in headers
|
||||
const response = NextResponse.next();
|
||||
const requestHeaders = new Headers(request.headers);
|
||||
requestHeaders.set("x-locale", localeFromPath);
|
||||
requestHeaders.set("x-pathname", pathname);
|
||||
|
||||
return NextResponse.next({
|
||||
request: {
|
||||
headers: requestHeaders,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: [
|
||||
// Match all pathnames except for
|
||||
// - … if they start with `/api`, `/_next` or `/_vercel`
|
||||
// - … the ones containing a dot (e.g. `favicon.ico`)
|
||||
'/((?!api|_next|_vercel|.*\\..*).*)',
|
||||
],
|
||||
};
|
||||
@@ -1,11 +1,23 @@
|
||||
import createNextIntlPlugin from 'next-intl/plugin'
|
||||
|
||||
const withNextIntl = createNextIntlPlugin('./i18n/request.ts')
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
eslint: {
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
typescript: {
|
||||
ignoreBuildErrors: true,
|
||||
},
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
webpack: (config) => {
|
||||
config.resolve.alias.canvas = false;
|
||||
|
||||
return config;
|
||||
},
|
||||
}
|
||||
|
||||
export default nextConfig
|
||||
export default withNextIntl(nextConfig)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@formatjs/intl-localematcher": "^0.8.0",
|
||||
"@hookform/resolvers": "^3.10.0",
|
||||
"@radix-ui/react-accordion": "1.2.2",
|
||||
"@radix-ui/react-alert-dialog": "1.1.4",
|
||||
@@ -44,9 +45,12 @@
|
||||
"cmdk": "1.0.4",
|
||||
"date-fns": "4.1.0",
|
||||
"embla-carousel-react": "8.5.1",
|
||||
"framer-motion": "^12.29.2",
|
||||
"input-otp": "1.4.1",
|
||||
"lucide-react": "^0.454.0",
|
||||
"negotiator": "^1.0.0",
|
||||
"next": "16.0.10",
|
||||
"next-intl": "^4.7.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "19.2.0",
|
||||
"react-day-picker": "9.8.0",
|
||||
@@ -64,6 +68,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.9",
|
||||
"@types/negotiator": "^0.6.4",
|
||||
"@types/node": "^22",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
|
||||
486
pnpm-lock.yaml
generated
486
pnpm-lock.yaml
generated
@@ -8,6 +8,9 @@ importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@formatjs/intl-localematcher':
|
||||
specifier: ^0.8.0
|
||||
version: 0.8.0
|
||||
'@hookform/resolvers':
|
||||
specifier: ^3.10.0
|
||||
version: 3.10.0(react-hook-form@7.71.1(react@19.2.0))
|
||||
@@ -113,15 +116,24 @@ importers:
|
||||
embla-carousel-react:
|
||||
specifier: 8.5.1
|
||||
version: 8.5.1(react@19.2.0)
|
||||
framer-motion:
|
||||
specifier: ^12.29.2
|
||||
version: 12.29.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
input-otp:
|
||||
specifier: 1.4.1
|
||||
version: 1.4.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
lucide-react:
|
||||
specifier: ^0.454.0
|
||||
version: 0.454.0(react@19.2.0)
|
||||
negotiator:
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
next:
|
||||
specifier: 16.0.10
|
||||
version: 16.0.10(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
next-intl:
|
||||
specifier: ^4.7.0
|
||||
version: 4.7.0(next@16.0.10(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
|
||||
next-themes:
|
||||
specifier: ^0.4.6
|
||||
version: 0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
@@ -168,6 +180,9 @@ importers:
|
||||
'@tailwindcss/postcss':
|
||||
specifier: ^4.1.9
|
||||
version: 4.1.18
|
||||
'@types/negotiator':
|
||||
specifier: ^0.6.4
|
||||
version: 0.6.4
|
||||
'@types/node':
|
||||
specifier: ^22
|
||||
version: 22.19.7
|
||||
@@ -221,6 +236,30 @@ packages:
|
||||
'@floating-ui/utils@0.2.10':
|
||||
resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
|
||||
|
||||
'@formatjs/ecma402-abstract@2.3.6':
|
||||
resolution: {integrity: sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw==}
|
||||
|
||||
'@formatjs/fast-memoize@2.2.7':
|
||||
resolution: {integrity: sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==}
|
||||
|
||||
'@formatjs/fast-memoize@3.1.0':
|
||||
resolution: {integrity: sha512-b5mvSWCI+XVKiz5WhnBCY3RJ4ZwfjAidU0yVlKa3d3MSgKmH1hC3tBGEAtYyN5mqL7N0G5x0BOUYyO8CEupWgg==}
|
||||
|
||||
'@formatjs/icu-messageformat-parser@2.11.4':
|
||||
resolution: {integrity: sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw==}
|
||||
|
||||
'@formatjs/icu-skeleton-parser@1.8.16':
|
||||
resolution: {integrity: sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ==}
|
||||
|
||||
'@formatjs/intl-localematcher@0.5.10':
|
||||
resolution: {integrity: sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q==}
|
||||
|
||||
'@formatjs/intl-localematcher@0.6.2':
|
||||
resolution: {integrity: sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA==}
|
||||
|
||||
'@formatjs/intl-localematcher@0.8.0':
|
||||
resolution: {integrity: sha512-zgMYWdUlmEZpX2Io+v3LHrfq9xZ6khpQVf9UAw2xYWhGerGgI9XgH1HvL/A34jWiruUJpYlP5pk4g8nIcaDrXQ==}
|
||||
|
||||
'@hookform/resolvers@3.10.0':
|
||||
resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==}
|
||||
peerDependencies:
|
||||
@@ -430,6 +469,88 @@ packages:
|
||||
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]
|
||||
|
||||
'@parcel/watcher-linux-arm-musl@2.5.6':
|
||||
resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@parcel/watcher-linux-arm64-glibc@2.5.6':
|
||||
resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@parcel/watcher-linux-arm64-musl@2.5.6':
|
||||
resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@parcel/watcher-linux-x64-glibc@2.5.6':
|
||||
resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@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]
|
||||
|
||||
'@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'}
|
||||
|
||||
'@radix-ui/number@1.1.0':
|
||||
resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==}
|
||||
|
||||
@@ -1086,9 +1207,87 @@ packages:
|
||||
'@radix-ui/rect@1.1.0':
|
||||
resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
|
||||
|
||||
'@schummar/icu-type-parser@1.21.5':
|
||||
resolution: {integrity: sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==}
|
||||
|
||||
'@swc/core-darwin-arm64@1.15.10':
|
||||
resolution: {integrity: sha512-U72pGqmJYbjrLhMndIemZ7u9Q9owcJczGxwtfJlz/WwMaGYAV/g4nkGiUVk/+QSX8sFCAjanovcU1IUsP2YulA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@swc/core-darwin-x64@1.15.10':
|
||||
resolution: {integrity: sha512-NZpDXtwHH083L40xdyj1sY31MIwLgOxKfZEAGCI8xHXdHa+GWvEiVdGiu4qhkJctoHFzAEc7ZX3GN5phuJcPuQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@swc/core-linux-arm-gnueabihf@1.15.10':
|
||||
resolution: {integrity: sha512-ioieF5iuRziUF1HkH1gg1r93e055dAdeBAPGAk40VjqpL5/igPJ/WxFHGvc6WMLhUubSJI4S0AiZAAhEAp1jDg==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-arm64-gnu@1.15.10':
|
||||
resolution: {integrity: sha512-tD6BClOrxSsNus9cJL7Gxdv7z7Y2hlyvZd9l0NQz+YXzmTWqnfzLpg16ovEI7gknH2AgDBB5ywOsqu8hUgSeEQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-arm64-musl@1.15.10':
|
||||
resolution: {integrity: sha512-4uAHO3nbfbrTcmO/9YcVweTQdx5fN3l7ewwl5AEK4yoC4wXmoBTEPHAVdKNe4r9+xrTgd4BgyPsy0409OjjlMw==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-x64-gnu@1.15.10':
|
||||
resolution: {integrity: sha512-W0h9ONNw1pVIA0cN7wtboOSTl4Jk3tHq+w2cMPQudu9/+3xoCxpFb9ZdehwCAk29IsvdWzGzY6P7dDVTyFwoqg==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-x64-musl@1.15.10':
|
||||
resolution: {integrity: sha512-XQNZlLZB62S8nAbw7pqoqwy91Ldy2RpaMRqdRN3T+tAg6Xg6FywXRKCsLh6IQOadr4p1+lGnqM/Wn35z5a/0Vw==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-win32-arm64-msvc@1.15.10':
|
||||
resolution: {integrity: sha512-qnAGrRv5Nj/DATxAmCnJQRXXQqnJwR0trxLndhoHoxGci9MuguNIjWahS0gw8YZFjgTinbTxOwzatkoySihnmw==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@swc/core-win32-ia32-msvc@1.15.10':
|
||||
resolution: {integrity: sha512-i4X/q8QSvzVlaRtv1xfnfl+hVKpCfiJ+9th484rh937fiEZKxZGf51C+uO0lfKDP1FfnT6C1yBYwHy7FLBVXFw==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@swc/core-win32-x64-msvc@1.15.10':
|
||||
resolution: {integrity: sha512-HvY8XUFuoTXn6lSccDLYFlXv1SU/PzYi4PyUqGT++WfTnbw/68N/7BdUZqglGRwiSqr0qhYt/EhmBpULj0J9rA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@swc/core@1.15.10':
|
||||
resolution: {integrity: sha512-udNofxftduMUEv7nqahl2nvodCiCDQ4Ge0ebzsEm6P8s0RC2tBM0Hqx0nNF5J/6t9uagFJyWIDjXy3IIWMHDJw==}
|
||||
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.25':
|
||||
resolution: {integrity: sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==}
|
||||
|
||||
'@tailwindcss/node@4.1.18':
|
||||
resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==}
|
||||
|
||||
@@ -1204,6 +1403,9 @@ packages:
|
||||
'@types/d3-timer@3.0.2':
|
||||
resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==}
|
||||
|
||||
'@types/negotiator@0.6.4':
|
||||
resolution: {integrity: sha512-elf6BsTq+AkyNsb2h5cGNst2Mc7dPliVoAPm1fXglC/BM3f2pFA40BaSSv3E5lyHteEawVKLP+8TwiY1DMNb3A==}
|
||||
|
||||
'@types/node@22.19.7':
|
||||
resolution: {integrity: sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==}
|
||||
|
||||
@@ -1321,6 +1523,9 @@ packages:
|
||||
decimal.js-light@2.5.1:
|
||||
resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
|
||||
|
||||
decimal.js@10.6.0:
|
||||
resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
|
||||
|
||||
detect-libc@2.1.2:
|
||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -1365,6 +1570,20 @@ packages:
|
||||
fraction.js@5.3.4:
|
||||
resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==}
|
||||
|
||||
framer-motion@12.29.2:
|
||||
resolution: {integrity: sha512-lSNRzBJk4wuIy0emYQ/nfZ7eWhqud2umPKw2QAQki6uKhZPKm2hRQHeQoHTG9MIvfobb+A/LbEWPJU794ZUKrg==}
|
||||
peerDependencies:
|
||||
'@emotion/is-prop-valid': '*'
|
||||
react: ^18.0.0 || ^19.0.0
|
||||
react-dom: ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@emotion/is-prop-valid':
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
|
||||
get-nonce@1.0.1:
|
||||
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -1382,6 +1601,17 @@ packages:
|
||||
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
intl-messageformat@10.7.18:
|
||||
resolution: {integrity: sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g==}
|
||||
|
||||
is-extglob@2.1.1:
|
||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-glob@4.0.3:
|
||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
jiti@2.6.1:
|
||||
resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
|
||||
hasBin: true
|
||||
@@ -1474,11 +1704,34 @@ packages:
|
||||
magic-string@0.30.21:
|
||||
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||
|
||||
motion-dom@12.29.2:
|
||||
resolution: {integrity: sha512-/k+NuycVV8pykxyiTCoFzIVLA95Nb1BFIVvfSu9L50/6K6qNeAYtkxXILy/LRutt7AzaYDc2myj0wkCVVYAPPA==}
|
||||
|
||||
motion-utils@12.29.2:
|
||||
resolution: {integrity: sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==}
|
||||
|
||||
nanoid@3.3.11:
|
||||
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
negotiator@1.0.0:
|
||||
resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
next-intl-swc-plugin-extractor@4.7.0:
|
||||
resolution: {integrity: sha512-iAqflu2FWdQMWhwB0B2z52X7LmEpvnMNJXqVERZQ7bK5p9iqQLu70ur6Ka6NfiXLxfb+AeAkUX5qIciQOg+87A==}
|
||||
|
||||
next-intl@4.7.0:
|
||||
resolution: {integrity: sha512-gvROzcNr/HM0jTzQlKWQxUNk8jrZ0bREz+bht3wNbv+uzlZ5Kn3J+m+viosub18QJ72S08UJnVK50PXWcUvwpQ==}
|
||||
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: ^5.0.0
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
next-themes@0.4.6:
|
||||
resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==}
|
||||
peerDependencies:
|
||||
@@ -1506,6 +1759,9 @@ packages:
|
||||
sass:
|
||||
optional: true
|
||||
|
||||
node-addon-api@7.1.1:
|
||||
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
|
||||
|
||||
node-releases@2.0.27:
|
||||
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
|
||||
|
||||
@@ -1516,6 +1772,13 @@ packages:
|
||||
picocolors@1.1.1:
|
||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||
|
||||
picomatch@4.0.3:
|
||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
po-parser@2.1.1:
|
||||
resolution: {integrity: sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==}
|
||||
|
||||
postcss-value-parser@4.2.0:
|
||||
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
|
||||
|
||||
@@ -1711,6 +1974,11 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
use-intl@4.7.0:
|
||||
resolution: {integrity: sha512-jyd8nSErVRRsSlUa+SDobKHo9IiWs5fjcPl9VBUnzUyEQpVM5mwJCgw8eUiylhvBpLQzUGox1KN0XlRivSID9A==}
|
||||
peerDependencies:
|
||||
react: ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0
|
||||
|
||||
use-sidecar@1.1.3:
|
||||
resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -1768,6 +2036,45 @@ snapshots:
|
||||
|
||||
'@floating-ui/utils@0.2.10': {}
|
||||
|
||||
'@formatjs/ecma402-abstract@2.3.6':
|
||||
dependencies:
|
||||
'@formatjs/fast-memoize': 2.2.7
|
||||
'@formatjs/intl-localematcher': 0.6.2
|
||||
decimal.js: 10.6.0
|
||||
tslib: 2.8.1
|
||||
|
||||
'@formatjs/fast-memoize@2.2.7':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@formatjs/fast-memoize@3.1.0':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@formatjs/icu-messageformat-parser@2.11.4':
|
||||
dependencies:
|
||||
'@formatjs/ecma402-abstract': 2.3.6
|
||||
'@formatjs/icu-skeleton-parser': 1.8.16
|
||||
tslib: 2.8.1
|
||||
|
||||
'@formatjs/icu-skeleton-parser@1.8.16':
|
||||
dependencies:
|
||||
'@formatjs/ecma402-abstract': 2.3.6
|
||||
tslib: 2.8.1
|
||||
|
||||
'@formatjs/intl-localematcher@0.5.10':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@formatjs/intl-localematcher@0.6.2':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@formatjs/intl-localematcher@0.8.0':
|
||||
dependencies:
|
||||
'@formatjs/fast-memoize': 3.1.0
|
||||
tslib: 2.8.1
|
||||
|
||||
'@hookform/resolvers@3.10.0(react-hook-form@7.71.1(react@19.2.0))':
|
||||
dependencies:
|
||||
react-hook-form: 7.71.1(react@19.2.0)
|
||||
@@ -1914,6 +2221,66 @@ snapshots:
|
||||
'@next/swc-win32-x64-msvc@16.0.10':
|
||||
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.3
|
||||
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
|
||||
|
||||
'@radix-ui/number@1.1.0': {}
|
||||
|
||||
'@radix-ui/primitive@1.1.1': {}
|
||||
@@ -2606,10 +2973,64 @@ snapshots:
|
||||
|
||||
'@radix-ui/rect@1.1.0': {}
|
||||
|
||||
'@schummar/icu-type-parser@1.21.5': {}
|
||||
|
||||
'@swc/core-darwin-arm64@1.15.10':
|
||||
optional: true
|
||||
|
||||
'@swc/core-darwin-x64@1.15.10':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-arm-gnueabihf@1.15.10':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-arm64-gnu@1.15.10':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-arm64-musl@1.15.10':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-x64-gnu@1.15.10':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-x64-musl@1.15.10':
|
||||
optional: true
|
||||
|
||||
'@swc/core-win32-arm64-msvc@1.15.10':
|
||||
optional: true
|
||||
|
||||
'@swc/core-win32-ia32-msvc@1.15.10':
|
||||
optional: true
|
||||
|
||||
'@swc/core-win32-x64-msvc@1.15.10':
|
||||
optional: true
|
||||
|
||||
'@swc/core@1.15.10':
|
||||
dependencies:
|
||||
'@swc/counter': 0.1.3
|
||||
'@swc/types': 0.1.25
|
||||
optionalDependencies:
|
||||
'@swc/core-darwin-arm64': 1.15.10
|
||||
'@swc/core-darwin-x64': 1.15.10
|
||||
'@swc/core-linux-arm-gnueabihf': 1.15.10
|
||||
'@swc/core-linux-arm64-gnu': 1.15.10
|
||||
'@swc/core-linux-arm64-musl': 1.15.10
|
||||
'@swc/core-linux-x64-gnu': 1.15.10
|
||||
'@swc/core-linux-x64-musl': 1.15.10
|
||||
'@swc/core-win32-arm64-msvc': 1.15.10
|
||||
'@swc/core-win32-ia32-msvc': 1.15.10
|
||||
'@swc/core-win32-x64-msvc': 1.15.10
|
||||
|
||||
'@swc/counter@0.1.3': {}
|
||||
|
||||
'@swc/helpers@0.5.15':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@swc/types@0.1.25':
|
||||
dependencies:
|
||||
'@swc/counter': 0.1.3
|
||||
|
||||
'@tailwindcss/node@4.1.18':
|
||||
dependencies:
|
||||
'@jridgewell/remapping': 2.3.5
|
||||
@@ -2703,6 +3124,8 @@ snapshots:
|
||||
|
||||
'@types/d3-timer@3.0.2': {}
|
||||
|
||||
'@types/negotiator@0.6.4': {}
|
||||
|
||||
'@types/node@22.19.7':
|
||||
dependencies:
|
||||
undici-types: 6.21.0
|
||||
@@ -2813,6 +3236,8 @@ snapshots:
|
||||
|
||||
decimal.js-light@2.5.1: {}
|
||||
|
||||
decimal.js@10.6.0: {}
|
||||
|
||||
detect-libc@2.1.2: {}
|
||||
|
||||
detect-node-es@1.1.0: {}
|
||||
@@ -2849,6 +3274,15 @@ snapshots:
|
||||
|
||||
fraction.js@5.3.4: {}
|
||||
|
||||
framer-motion@12.29.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
|
||||
dependencies:
|
||||
motion-dom: 12.29.2
|
||||
motion-utils: 12.29.2
|
||||
tslib: 2.8.1
|
||||
optionalDependencies:
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
|
||||
get-nonce@1.0.1: {}
|
||||
|
||||
graceful-fs@4.2.11: {}
|
||||
@@ -2860,6 +3294,19 @@ snapshots:
|
||||
|
||||
internmap@2.0.3: {}
|
||||
|
||||
intl-messageformat@10.7.18:
|
||||
dependencies:
|
||||
'@formatjs/ecma402-abstract': 2.3.6
|
||||
'@formatjs/fast-memoize': 2.2.7
|
||||
'@formatjs/icu-messageformat-parser': 2.11.4
|
||||
tslib: 2.8.1
|
||||
|
||||
is-extglob@2.1.1: {}
|
||||
|
||||
is-glob@4.0.3:
|
||||
dependencies:
|
||||
is-extglob: 2.1.1
|
||||
|
||||
jiti@2.6.1: {}
|
||||
|
||||
js-tokens@4.0.0: {}
|
||||
@@ -2927,8 +3374,34 @@ snapshots:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
motion-dom@12.29.2:
|
||||
dependencies:
|
||||
motion-utils: 12.29.2
|
||||
|
||||
motion-utils@12.29.2: {}
|
||||
|
||||
nanoid@3.3.11: {}
|
||||
|
||||
negotiator@1.0.0: {}
|
||||
|
||||
next-intl-swc-plugin-extractor@4.7.0: {}
|
||||
|
||||
next-intl@4.7.0(next@16.0.10(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@formatjs/intl-localematcher': 0.5.10
|
||||
'@parcel/watcher': 2.5.6
|
||||
'@swc/core': 1.15.10
|
||||
negotiator: 1.0.0
|
||||
next: 16.0.10(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
next-intl-swc-plugin-extractor: 4.7.0
|
||||
po-parser: 2.1.1
|
||||
react: 19.2.0
|
||||
use-intl: 4.7.0(react@19.2.0)
|
||||
optionalDependencies:
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- '@swc/helpers'
|
||||
|
||||
next-themes@0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
@@ -2957,12 +3430,18 @@ snapshots:
|
||||
- '@babel/core'
|
||||
- babel-plugin-macros
|
||||
|
||||
node-addon-api@7.1.1: {}
|
||||
|
||||
node-releases@2.0.27: {}
|
||||
|
||||
object-assign@4.1.1: {}
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
||||
picomatch@4.0.3: {}
|
||||
|
||||
po-parser@2.1.1: {}
|
||||
|
||||
postcss-value-parser@4.2.0: {}
|
||||
|
||||
postcss@8.4.31:
|
||||
@@ -3162,6 +3641,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.9
|
||||
|
||||
use-intl@4.7.0(react@19.2.0):
|
||||
dependencies:
|
||||
'@formatjs/fast-memoize': 2.2.7
|
||||
'@schummar/icu-type-parser': 1.21.5
|
||||
intl-messageformat: 10.7.18
|
||||
react: 19.2.0
|
||||
|
||||
use-sidecar@1.1.3(@types/react@19.2.9)(react@19.2.0):
|
||||
dependencies:
|
||||
detect-node-es: 1.1.0
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
BIN
public/images/homeBanner.png
Normal file
BIN
public/images/homeBanner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
Reference in New Issue
Block a user