32b4460b66
Добавляет zh-CN, fa, ar, tr, uk, be, vi, uz словари (170 ключей, идентичная
вложенная структура) к существующим en/ru. lib/locales.ts — единый источник
списка локалей/дефолтной локали/RTL-набора вместо захардкоженного ["en","ru"]
в proxy.ts. language-switcher.tsx: переключение языка резало только
двухбуквенные коды регэкспом (/^\/[a-z]{2}/), из-за чего zh-CN никогда не
матчился и путь задваивался — заменено на honest-поиск по списку locales.
app/[lang]/layout.tsx — dir="rtl"/"ltr" на <html> по локали (SSR, в отличие
от реактивного клиентского переключения в netrunner-app). Header.tsx/
Footer.tsx — разбитое на три <span> имя бренда визуально переворачивалось
Flexbox'ом под dir=rtl ("VPNrunnerNet"), исправлено через dir="ltr" на
самом враппере.
BlogPreview/Faq/Pricing и обе blog-страницы: fallback на *_en-коллекцию
PocketBase, если для языка ещё нет переведённого контента (FAQ-ответы,
детали тарифов, посты блога не тянутся автоматически — это отдельный от
статических словарей CMS-контент), плюс i18n-ключи period1m/period6m/
period1y вместо захардкоженных ru/en-подписей периодов в Pricing.tsx.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
171 lines
6.3 KiB
TypeScript
171 lines
6.3 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { JetBrains_Mono } from "next/font/google";
|
|
import { Dictionary } from "@/lib/IDict";
|
|
import { socialLinks, FlickeringSocialIcon } from "@/components/ui/social-links";
|
|
|
|
const jetbrainsMono = JetBrains_Mono({
|
|
subsets: ["latin", "cyrillic"],
|
|
});
|
|
|
|
export function Footer({
|
|
dict,
|
|
lang,
|
|
}: {
|
|
dict: Dictionary["footer"];
|
|
lang: string;
|
|
}) {
|
|
const sitemap = [
|
|
{
|
|
title: dict.sections.product,
|
|
links: [
|
|
{ name: dict.links.features, href: `/${lang}#features` },
|
|
{ name: dict.links.pricing, href: `/${lang}#pricing` },
|
|
{ name: dict.links.protocol, href: `/${lang}/docs` },
|
|
{ name: dict.links.profile, href: `/${lang}/auth` },
|
|
],
|
|
},
|
|
{
|
|
title: dict.sections.resources,
|
|
links: [
|
|
{ name: dict.links.faq, href: `/${lang}#faq` },
|
|
{ name: dict.links.comms, href: `/${lang}/blog` },
|
|
],
|
|
},
|
|
{
|
|
title: dict.sections.legal,
|
|
links: [
|
|
{ name: dict.links.privacy, href: `/${lang}/docs` },
|
|
{ name: dict.links.terms, href: `/${lang}/docs` },
|
|
],
|
|
},
|
|
];
|
|
|
|
return (
|
|
<footer
|
|
className={`mt-20 border-t border-border/20 bg-background pt-16 pb-12 ${jetbrainsMono.className}`}
|
|
>
|
|
<div className="container mx-auto px-6 max-w-6xl">
|
|
<div className="flex flex-col lg:flex-row justify-between items-start gap-16 lg:gap-8">
|
|
<div className="flex flex-col gap-3 max-w-xs">
|
|
<Link
|
|
href={`/${lang}`}
|
|
className="flex items-center gap-3 group hover:scale-105 transition-transform duration-300 w-fit mt-1"
|
|
>
|
|
<div
|
|
dir="ltr"
|
|
className="text-2xl sm:text-3xl tracking-widest flex items-center select-none font-bold"
|
|
>
|
|
<span
|
|
className="text-transparent animate-neon-flicker transition-all duration-300"
|
|
style={{
|
|
WebkitTextStroke: "1px #00E5F2",
|
|
filter: "drop-shadow(0 0 5px rgba(0,229,242,0.6))",
|
|
}}
|
|
>
|
|
Net
|
|
</span>
|
|
<span
|
|
className="text-transparent transition-all duration-300"
|
|
style={{
|
|
WebkitTextStroke: "1px #00E5F2",
|
|
filter: "drop-shadow(0 0 5px rgba(0,229,242,0.6))",
|
|
}}
|
|
>
|
|
runner
|
|
</span>
|
|
<span
|
|
className="ml-2 text-transparent opacity-90 group-hover:opacity-100 transition-all duration-300"
|
|
style={{
|
|
WebkitTextStroke: "1px #8B3DFF",
|
|
filter: "drop-shadow(0 0 5px rgba(139,61,255,0.6))",
|
|
}}
|
|
>
|
|
VPN
|
|
</span>
|
|
</div>
|
|
</Link>
|
|
|
|
<div className="text-xs font-bold text-primary/80 tracking-widest uppercase mt-1 drop-shadow-[0_0_5px_rgba(139,61,255,0.5)]">
|
|
{dict.protocolStatus}
|
|
</div>
|
|
|
|
<p className="text-muted-foreground text-sm leading-relaxed mt-2 max-w-50">
|
|
{dict.tagline}
|
|
</p>
|
|
|
|
<div className="flex flex-wrap gap-5 mt-4 items-center">
|
|
{socialLinks.map((social) => (
|
|
<FlickeringSocialIcon key={social.name} social={social} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex flex-wrap md:flex-nowrap gap-12 lg:gap-16">
|
|
{sitemap.map((section, idx) => (
|
|
<div key={idx} className="flex flex-col gap-5">
|
|
<h4 className="text-foreground font-black text-[13px] uppercase tracking-widest">
|
|
{section.title}
|
|
</h4>
|
|
<ul className="flex flex-col gap-3">
|
|
{section.links.map((link, linkIdx) => (
|
|
<li key={linkIdx}>
|
|
<Link
|
|
href={link.href}
|
|
className="text-muted-foreground hover:text-primary text-sm transition-colors duration-200"
|
|
>
|
|
{link.name}
|
|
</Link>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-20 border border-border/30 bg-card/20 rounded-xl p-6 md:px-10 md:py-8 flex flex-col md:flex-row justify-between items-start md:items-center gap-8 shadow-2xl relative overflow-hidden">
|
|
<div className="absolute top-0 left-1/4 w-1/2 h-full bg-primary/10 blur-3xl -z-10 pointer-events-none" />
|
|
|
|
<div className="flex flex-col gap-1">
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-1.5 h-1.5 rounded-full bg-primary shadow-[0_0_8px_rgba(139,61,255,0.8)] animate-pulse" />
|
|
<span className="text-[10px] text-muted-foreground/60 uppercase tracking-widest font-bold">
|
|
{dict.uplinkStatus}
|
|
</span>
|
|
</div>
|
|
<div className="text-2xl font-black text-foreground tracking-tight mt-1">
|
|
464.6 MBPS
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex flex-col gap-1">
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-1.5 h-1.5 rounded-full bg-primary shadow-[0_0_8px_rgba(139,61,255,0.8)]" />
|
|
<span className="text-[10px] text-muted-foreground/60 uppercase tracking-widest font-bold">
|
|
{dict.activeNode}
|
|
</span>
|
|
</div>
|
|
<div className="text-2xl font-black text-foreground tracking-tight mt-1">
|
|
TYO-SEC-05
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex flex-col gap-1">
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-1.5 h-1.5 rounded-full bg-green-500 shadow-[0_0_8px_rgba(34,197,94,0.8)]" />
|
|
<span className="text-[10px] text-muted-foreground/60 uppercase tracking-widest font-bold">
|
|
{dict.latency}
|
|
</span>
|
|
</div>
|
|
<div className="text-2xl font-black text-foreground tracking-tight mt-1">
|
|
16 MS
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
);
|
|
}
|