Files
trustlab/src/app/(public)/HomeClient.tsx

547 lines
34 KiB
TypeScript

"use client";
import Link from "next/link";
import CommonGridShape from "@/components/common/CommonGridShape";
import { useEffect, useState } from "react";
import axios from '@/lib/axios';
import { useTranslations } from "next-intl";
interface CaCertificate {
name: string;
type: string;
serial: string;
expires_at: string;
last_synced_at?: string | null;
cdn_url?: string | null;
der_cdn_url?: string | null;
bat_cdn_url?: string | null;
mac_cdn_url?: string | null;
linux_cdn_url?: string | null;
}
// Simple internal ScrollToTop component
function ScrollToTop() {
const [show, setShow] = useState(false);
useEffect(() => {
const handleScroll = () => {
setShow(window.pageYOffset > 500);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const scrollToTop = () => {
const element = document.querySelector('#home');
if (element) {
const navbarOffset = 80;
const elementPosition = element.getBoundingClientRect().top;
const offsetPosition = elementPosition + window.pageYOffset - navbarOffset;
window.scrollTo({
top: offsetPosition,
behavior: "smooth",
});
}
};
if (!show) return null;
return (
<button
onClick={scrollToTop}
className="fixed bottom-8 right-8 z-50 p-4 bg-brand-500 hover:bg-brand-600 text-white rounded-2xl shadow-2xl shadow-brand-500/40 transition-all hover:-translate-y-1 active:scale-95 animate-in fade-in slide-in-from-bottom-5"
aria-label="Back to top"
>
<svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 10l7-7m0 0l7 7m-7-7v18" />
</svg>
</button>
);
}
// UI Sub-components
function Badge({ children, variant = 'brand' }: { children: React.ReactNode, variant?: 'brand' | 'blue' | 'purple' | 'green' | 'gray' }) {
const variants = {
brand: 'bg-brand-50 text-brand-700 dark:bg-brand-500/10 dark:text-brand-400 border-brand-100 dark:border-brand-500/20',
blue: 'bg-blue-50 text-blue-700 dark:bg-blue-500/10 dark:text-blue-400 border-blue-100 dark:border-blue-500/20',
purple: 'bg-purple-50 text-purple-700 dark:bg-purple-500/10 dark:text-purple-400 border-purple-100 dark:border-purple-500/20',
green: 'bg-green-50 text-green-700 dark:bg-green-500/10 dark:text-green-400 border-green-100 dark:border-green-500/20',
gray: 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400 border-gray-200 dark:border-gray-700',
};
return (
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-bold uppercase tracking-wider border ${variants[variant]}`}>
{children}
</span>
);
}
function TabButton({ id, label, active, onClick, icon }: { id: string, label: string, active: boolean, onClick: () => void, icon?: React.ReactNode }) {
return (
<button
onClick={onClick}
className={`flex items-center gap-2 px-5 py-2.5 rounded-xl text-sm font-bold transition-all duration-300 ${
active
? 'bg-white dark:bg-gray-700 text-brand-600 dark:text-brand-400 shadow-sm'
: 'text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200'
}`}
>
{icon}
{label}
</button>
);
}
function OsGuideContent({ title, steps }: { title: string, steps: string[] }) {
return (
<div className="p-6 bg-white dark:bg-gray-800 rounded-2xl border border-gray-100 dark:border-gray-700 shadow-sm">
<h4 className="text-lg font-bold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<div className="w-1.5 h-6 bg-brand-500 rounded-full"></div>
{title}
</h4>
<ul className="space-y-4">
{steps.map((step, idx) => {
const isCommand = step.includes('curl') || step.includes('bash') || step.includes('sudo');
return (
<li key={idx} className="flex gap-4">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-50 dark:bg-brand-500/10 text-brand-600 dark:text-brand-400 flex items-center justify-center text-xs font-bold border border-brand-100 dark:border-brand-500/20">
{idx + 1}
</span>
<div className="flex-1">
<p className={`text-sm text-gray-600 dark:text-gray-400 leading-relaxed ${isCommand ? 'font-mono bg-gray-100 dark:bg-gray-900 px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 break-all' : 'font-medium'}`}>
{step}
</p>
</div>
</li>
);
})}
</ul>
</div>
);
}
function CaCard({ cert, isRoot, t, selectedOs, setSelectedOs }: { cert: CaCertificate, isRoot: boolean, t: any, selectedOs: string, setSelectedOs: (os: any) => void }) {
const [copied, setCopied] = useState(false);
const copyLinuxCli = () => {
if (!cert.linux_cdn_url) return;
const command = `curl -sL ${cert.linux_cdn_url} | sudo bash`;
navigator.clipboard.writeText(command);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<div className="group relative bg-white/40 dark:bg-gray-900/40 backdrop-blur-xl rounded-[2.5rem] p-8 border border-white/50 dark:border-gray-800/50 shadow-xl hover:shadow-2xl transition-all duration-500 hover:-translate-y-1">
{/* Sync Status Badge */}
{cert.last_synced_at && (
<div className="absolute top-6 right-8 flex items-center gap-1.5 px-2 py-1 rounded-lg bg-green-500/10 border border-green-500/20 text-[10px] font-bold text-green-600 dark:text-green-400 uppercase tracking-tighter">
<span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
</span>
{t('synced_to_cdn')}
</div>
)}
<div className="flex flex-col md:flex-row md:items-center justify-between gap-6 mb-8">
<div className="flex items-center gap-6">
<div className={`w-16 h-16 rounded-3xl flex items-center justify-center shadow-lg transition-transform group-hover:scale-110 duration-500 ${
isRoot ? 'bg-brand-500 text-white shadow-brand-500/20' : 'bg-blue-500 text-white shadow-blue-500/20'
}`}>
<svg className="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
</div>
<div>
<Badge variant={isRoot ? 'purple' : 'blue'}>
{isRoot ? t('root_ca') : t('intermediate_ca')}
</Badge>
<h4 className="text-2xl font-black text-gray-900 dark:text-white mt-1 group-hover:text-brand-500 transition-colors">{cert.name}</h4>
<div className="flex items-center gap-4 mt-2 font-mono text-[10px] text-gray-400">
<span className="flex items-center gap-1.5">
<span className="w-1 h-1 rounded-full bg-gray-400"></span>
ID: {cert.serial}
</span>
</div>
</div>
</div>
</div>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4">
<DownloadBtn
href={cert.cdn_url || `/api/public/ca-certificates/${cert.serial}/download`}
label={t('download_standard') || "PEM"}
icon={<FileIcon className="w-4 h-4" />}
onClick={() => {}}
/>
<DownloadBtn
href={cert.der_cdn_url || `/api/public/ca-certificates/${cert.serial}/download?format=der`}
label={t('download_android') || "Android/DER"}
icon={<MobileIcon className="w-4 h-4" />}
onClick={() => setSelectedOs('mobile')}
variant="green"
/>
<DownloadBtn
href={cert.bat_cdn_url || `/api/public/ca-certificates/${cert.serial}/download/windows`}
label={t('download_windows') || "Windows"}
icon={<WindowsIcon className="w-4 h-4" />}
onClick={() => setSelectedOs('windows')}
variant="blue"
/>
<DownloadBtn
href={cert.mac_cdn_url || `/api/public/ca-certificates/${cert.serial}/download/mac`}
label={t('download_macos') || "macOS"}
icon={<AppleIcon className="w-4 h-4" />}
onClick={() => setSelectedOs('macos')}
variant="gray"
/>
</div>
{cert.linux_cdn_url && (
<div className="mt-4 flex gap-3">
<DownloadBtn
href={cert.linux_cdn_url || `/api/public/ca-certificates/${cert.serial}/download/linux`}
label={t('download_linux') || "Linux (.sh)"}
icon={<LinuxIcon className="w-4 h-4" />}
onClick={() => setSelectedOs('linux')}
variant="gray"
isFullWidth
/>
<button
onClick={copyLinuxCli}
className={`flex items-center justify-center gap-2 px-6 py-3 rounded-2xl border font-bold text-xs transition-all duration-300 active:scale-95 ${
copied
? 'bg-green-500 text-white border-green-500 shadow-lg'
: 'bg-brand-500 text-white border-brand-500 hover:bg-brand-600 shadow-md hover:shadow-xl'
}`}
title="Copy CLI Command"
>
{copied ? <CheckIcon className="w-4 h-4" /> : <CopyIcon className="w-4 h-4" />}
{copied ? (t('copied') || "Copied!") : (t('copy_cli') || "Copy CLI")}
</button>
</div>
)}
</div>
);
}
function DownloadBtn({ href, label, icon, onClick, variant = 'white', isFullWidth = false }: { href: string, label: string, icon: React.ReactNode, onClick: () => void, variant?: 'white' | 'green' | 'blue' | 'gray', isFullWidth?: boolean }) {
const variants = {
white: 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200 border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700',
green: 'bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-400 border-green-200 dark:border-green-500/20 hover:bg-green-100 dark:hover:bg-green-500/20',
blue: 'bg-blue-50 dark:bg-blue-500/10 text-blue-700 dark:text-blue-400 border-blue-200 dark:border-blue-500/20 hover:bg-blue-100 dark:hover:bg-blue-500/20',
gray: 'bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-100 border-gray-200 dark:border-gray-600 hover:bg-gray-200 dark:hover:bg-gray-600',
};
return (
<a
href={href}
onClick={onClick}
target="_blank"
rel="noopener noreferrer"
className={`flex items-center justify-center gap-2 px-4 py-3 rounded-2xl border font-bold text-xs transition-all duration-300 hover:shadow-lg active:scale-95 ${variants[variant]} ${isFullWidth ? 'w-full' : ''}`}
>
{icon}
{label}
</a>
);
}
// Icons
const WindowsIcon = ({ className }: { className?: string }) => (
<svg className={className} viewBox="0 0 24 24" fill="currentColor">
<path d="M0 3.449L9.75 2.134V11.3L0 11.3V3.449ZM9.75 12.7L0 12.7V20.551L9.75 19.166V12.7ZM10.5 1.998L24 0.166V11.3L10.5 11.3V1.998ZM10.5 12.7L24 12.7V23.834L10.5 21.966V12.7Z"/>
</svg>
);
const AppleIcon = ({ className }: { className?: string }) => (
<svg className={className} viewBox="0 0 24 24" fill="currentColor">
<path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.21-1.96 1.07-3.11-1.05.05-2.31.74-3.03 1.59-.65.77-1.2 2.02-1.07 3.12 1.17.09 2.36-.73 3.03-1.6"/>
</svg>
);
const LinuxIcon = ({ className }: { className?: string }) => (
<svg className={className} viewBox="0 0 24 24" fill="currentColor">
<path d="M11.97 2c-3.14 0-5.69 2.51-5.69 5.61v.24c-.11-.03-.23-.05-.36-.05-1.16 0-2.11.93-2.11 2.07s.95 2.06 2.11 2.06c.13 0 .25-.01.36-.04v.24c0 3.1 2.55 5.61 5.69 5.61 3.14 0 5.69-2.51 5.69-5.61v-.24c.11.03.22.04.35.04 1.16 0 2.11-.93 2.11-2.06s-.95-2.07-2.11-2.07c-.13 0-.24.02-.35.05v-.24C17.66 4.51 15.11 2 11.97 2zm0 1.87c2.1 0 3.8 1.67 3.8 3.74v.17c-.38-.08-.78-.13-1.2-.13-2.13 0-3.86 1.69-3.86 3.78s1.73 3.78 3.86 3.78c.42 0 .82-.05 1.2-.13v.17c0 2.07-1.7 3.74-3.8 3.74-2.1 0-3.8-1.67-3.8-3.74v-.17c.38.08.78.13 1.2.13 2.13 0 3.86-1.69 3.86-3.78s-1.73-3.78-3.86-3.78c-.42 0-.82.05-1.2.13v-.17c0-2.07 1.7-3.74 3.8-3.74zM8.33 9.4c.58 0 1.05.47 1.05 1.04s-.47 1.04-1.05 1.04-1.05-.47-1.05-1.04.47-1.04 1.05-1.04zm7.28 0c.58 0 1.05.47 1.05 1.04s-.47 1.04-1.05 1.04-1.05-.47-1.05-1.04.47-1.04 1.05-1.04zM12 21c-1.1 0-2 .9-2 2h4c0-1.1-.9-2-2-2z"/>
</svg>
);
const MobileIcon = ({ className }: { className?: string }) => (
<svg className={className} viewBox="0 0 24 24" fill="currentColor">
<path d="M17 2H7c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 18H7V4h10v16z"/>
</svg>
);
const FileIcon = ({ className }: { className?: string }) => (
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
</svg>
);
const CopyIcon = ({ className }: { className?: string }) => (
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
</svg>
);
const CheckIcon = ({ className }: { className?: string }) => (
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 13l4 4L19 7" />
</svg>
);
export default function HomeClient() {
const t = useTranslations("Home");
const [certificates, setCertificates] = useState<CaCertificate[]>([]);
const [loadingCerts, setLoadingCerts] = useState(true);
const [selectedOs, setSelectedOs] = useState<'windows' | 'macos' | 'linux' | 'mobile'>('windows');
useEffect(() => {
const fetchCertificates = async () => {
try {
const response = await axios.get('/api/public/ca-certificates');
if (response.data.success) {
setCertificates(response.data.data);
}
} catch (error) {
console.error("Failed to fetch certificates", error);
} finally {
setLoadingCerts(false);
}
};
fetchCertificates();
}, []);
const handleScroll = (e: React.MouseEvent<HTMLAnchorElement>, id: string) => {
e.preventDefault();
const element = document.querySelector(id);
if (element) {
const navbarOffset = 80;
const elementPosition = element.getBoundingClientRect().top;
const offsetPosition = elementPosition + window.pageYOffset - navbarOffset;
window.scrollTo({
top: offsetPosition,
behavior: "smooth",
});
}
};
return (
<div className="relative flex-grow flex flex-col">
{/* Hero Section */}
<header className="relative pt-32 pb-20 overflow-hidden" id="home">
{/* Background Shapes */}
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-full max-w-7xl h-full -z-10 opacity-30 dark:opacity-20 pointer-events-none">
<div className="absolute top-20 left-10 w-72 h-72 bg-brand-500 rounded-full blur-[120px]"></div>
<div className="absolute bottom-10 right-10 w-96 h-96 bg-blue-500 rounded-full blur-[150px]"></div>
</div>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-brand-50 dark:bg-brand-500/10 border border-brand-100 dark:border-brand-500/20 text-brand-600 dark:text-brand-400 text-xs font-bold uppercase tracking-widest mb-8 animate-bounce">
🚀 {t('hero_tag')}
</div>
<h1 className="text-5xl md:text-7xl font-extrabold text-gray-900 dark:text-white mb-6 leading-tight">
{t('hero_title_1')} <br/>
<span className="text-transparent bg-clip-text bg-gradient-to-r from-brand-500 to-blue-600">
{t('hero_title_2')}
</span>
</h1>
<p className="text-lg md:text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto mb-10">
{t('hero_desc')}
</p>
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
<Link href="/signup" className="w-full sm:w-auto px-8 py-4 bg-gray-900 dark:bg-white text-white dark:text-gray-900 rounded-2xl font-bold shadow-xl transition-all hover:-translate-y-1 hover:shadow-2xl">
{t('cta_create_account')}
</Link>
<a href="#features" onClick={(e) => handleScroll(e, '#features')} className="w-full sm:w-auto px-8 py-4 bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200 border border-gray-200 dark:border-gray-700 rounded-2xl font-bold transition-all hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer">
{t('cta_explore_features')}
</a>
</div>
{/* Preview/Abstract UI */}
<div className="mt-20 relative mx-auto max-w-5xl">
<div className="aspect-video bg-white dark:bg-gray-800 rounded-3xl border border-gray-200 dark:border-gray-700 shadow-2xl p-4 overflow-hidden group">
<div className="flex items-center gap-2 mb-4 border-b border-gray-100 dark:border-gray-700 pb-3">
<div className="flex gap-1.5">
<div className="w-3 h-3 rounded-full bg-red-400"></div>
<div className="w-3 h-3 rounded-full bg-yellow-400"></div>
<div className="w-3 h-3 rounded-full bg-green-400"></div>
</div>
<div className="flex-1 ml-4 h-6 bg-gray-100 dark:bg-gray-900/50 rounded-lg max-w-xs"></div>
</div>
{/* Mock Dashboard Content */}
<div className="grid grid-cols-3 gap-4">
<div className="col-span-2 space-y-4">
<div className="h-40 bg-brand-500/5 rounded-2xl border border-brand-500/10"></div>
<div className="grid grid-cols-2 gap-4">
<div className="h-24 bg-gray-50 dark:bg-gray-900/50 rounded-2xl"></div>
<div className="h-24 bg-gray-50 dark:bg-gray-900/50 rounded-2xl"></div>
</div>
</div>
<div className="space-y-4">
<div className="h-full bg-gray-50 dark:bg-gray-900/50 rounded-2xl"></div>
</div>
</div>
{/* Overlay Gradient */}
<div className="absolute inset-0 bg-gradient-to-t from-white dark:from-gray-900 via-transparent to-transparent pointer-events-none"></div>
</div>
</div>
</div>
</header>
{/* Features Section */}
<section id="features" className="py-24 bg-gray-50 dark:bg-gray-900/50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 dark:text-white mb-4">{t('features_title')}</h2>
<p className="text-gray-600 dark:text-gray-400">{t('features_desc')}</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{/* Feature 1 */}
<div className="bg-white dark:bg-gray-800 p-8 rounded-3xl border border-gray-100 dark:border-gray-700 shadow-sm hover:shadow-xl transition-all duration-300 group">
<div className="w-14 h-14 bg-brand-50 dark:bg-brand-500/10 rounded-2xl flex items-center justify-center text-brand-500 mb-6 group-hover:scale-110 transition-transform">
<svg className="h-7 w-7" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
</div>
<h3 className="text-xl font-bold text-gray-900 dark:text-white mb-3">{t('feature_1_title')}</h3>
<p className="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">
{t('feature_1_desc')}
</p>
</div>
{/* Feature 2 */}
<div className="bg-white dark:bg-gray-800 p-8 rounded-3xl border border-gray-100 dark:border-gray-700 shadow-sm hover:shadow-xl transition-all duration-300 group">
<div className="w-14 h-14 bg-blue-50 dark:bg-blue-500/10 rounded-2xl flex items-center justify-center text-blue-500 mb-6 group-hover:scale-110 transition-transform">
<svg className="h-7 w-7" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11.536 11 9 13.536 7.464 12 4.929 14.536V17h2.472l4.243-4.243a6 6 0 018.828-5.743zM16.5 13.5V18h6v-4.5h-6z" />
</svg>
</div>
<h3 className="text-xl font-bold text-gray-900 dark:text-white mb-3">{t('feature_2_title')}</h3>
<p className="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">
{t('feature_2_desc')}
</p>
</div>
{/* Feature 3 */}
<div className="bg-white dark:bg-gray-800 p-8 rounded-3xl border border-gray-100 dark:border-gray-700 shadow-sm hover:shadow-xl transition-all duration-300 group">
<div className="w-14 h-14 bg-green-50 dark:bg-green-500/10 rounded-2xl flex items-center justify-center text-green-500 mb-6 group-hover:scale-110 transition-transform">
<svg className="h-7 w-7" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
</svg>
</div>
<h3 className="text-xl font-bold text-gray-900 dark:text-white mb-3">{t('feature_3_title')}</h3>
<p className="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">
{t('feature_3_desc')}
</p>
</div>
</div>
</div>
</section>
{/* Trust Store Section */}
<section id="trust-store" className="py-24 bg-white dark:bg-gray-800 relative overflow-hidden">
{/* Gradient Background */}
<div className="absolute inset-0 opacity-30 dark:opacity-10 pointer-events-none">
<div className="absolute -top-20 -right-20 w-96 h-96 bg-brand-500/20 rounded-full blur-[100px]"></div>
<div className="absolute -bottom-20 -left-20 w-80 h-80 bg-blue-500/20 rounded-full blur-[100px]"></div>
</div>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 dark:text-white mb-4">{t('trust_store_title')}</h2>
<p className="text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
{t('trust_store_desc')}
</p>
</div>
{loadingCerts ? (
<div className="flex justify-center py-12">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-brand-500"></div>
</div>
) : (
<div className="space-y-16">
{/* Root CA Section */}
<div className="flex flex-col items-center">
<h3 className="text-sm font-bold text-brand-500 uppercase tracking-widest mb-8 px-4 py-1 bg-brand-50 dark:bg-brand-500/10 rounded-full border border-brand-100 dark:border-brand-500/20">
{t('root_ca_hierarchy')}
</h3>
<div className="grid grid-cols-1 gap-8 w-full max-w-2xl px-4">
{certificates.filter(c => c.type === 'root').map((cert) => (
<CaCard key={cert.serial} cert={cert} isRoot={true} t={t} selectedOs={selectedOs} setSelectedOs={setSelectedOs} />
))}
</div>
</div>
{/* Intermediate CAs Section */}
<div className="flex flex-col items-center">
<div className="w-px h-12 bg-gradient-to-b from-brand-500/50 to-transparent mb-8"></div>
<h3 className="text-sm font-bold text-blue-500 uppercase tracking-widest mb-8 px-4 py-1 bg-blue-50 dark:bg-blue-500/10 rounded-full border border-blue-100 dark:border-blue-500/20">
{t('intermediate_ca_hierarchy')}
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 w-full max-w-6xl px-4">
{certificates.filter(c => c.type !== 'root').map((cert) => (
<CaCard key={cert.serial} cert={cert} isRoot={false} t={t} selectedOs={selectedOs} setSelectedOs={setSelectedOs} />
))}
</div>
</div>
{/* OS Selection Tabs for Global Guide */}
<div className="max-w-4xl mx-auto mt-20 p-8 rounded-[2rem] bg-gray-50 dark:bg-gray-900/50 border border-gray-100 dark:border-gray-800">
<div className="text-center mb-8">
<h3 className="text-2xl font-bold text-gray-900 dark:text-white mb-2">{t('install_guide_title')}</h3>
<p className="text-gray-600 dark:text-gray-400">{t('install_guide_desc')}</p>
</div>
<div className="flex flex-wrap justify-center gap-2 mb-8 p-1.5 bg-gray-200/50 dark:bg-gray-800/50 rounded-2xl">
<TabButton id="windows" label="Windows" active={selectedOs === 'windows'} onClick={() => setSelectedOs('windows')} icon={<WindowsIcon className="w-4 h-4" />} />
<TabButton id="macos" label="macOS" active={selectedOs === 'macos'} onClick={() => setSelectedOs('macos')} icon={<AppleIcon className="w-4 h-4" />} />
<TabButton id="linux" label="Linux" active={selectedOs === 'linux'} onClick={() => setSelectedOs('linux')} icon={<LinuxIcon className="w-4 h-4" />} />
<TabButton id="mobile" label="Android/iOS" active={selectedOs === 'mobile'} onClick={() => setSelectedOs('mobile')} icon={<MobileIcon className="w-4 h-4" />} />
</div>
<div className="space-y-4 animate-in fade-in slide-in-from-bottom-2 duration-500">
{selectedOs === 'windows' && <OsGuideContent title="Windows Installation" steps={t.raw('guide_steps_windows')} />}
{selectedOs === 'macos' && <OsGuideContent title="macOS Installation" steps={t.raw('guide_steps_macos')} />}
{selectedOs === 'linux' && <OsGuideContent title="Linux Installation" steps={t.raw('guide_steps_linux')} />}
{selectedOs === 'mobile' && <OsGuideContent title="Mobile Installation" steps={t.raw('guide_steps_mobile')} />}
</div>
</div>
</div>
)}
</div>
</section>
{/* CTA Section */}
<section className="py-20">
<div className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="bg-brand-600 rounded-[3rem] p-12 md:p-16 text-center text-white relative overflow-hidden shadow-2xl">
<div className="relative z-10">
<h2 className="text-3xl md:text-4xl font-bold mb-6">{t('cta_ready_title')}</h2>
<p className="text-brand-100 mb-10 max-w-lg mx-auto">{t('cta_ready_desc')}</p>
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
<Link href="/signup" className="px-8 py-4 bg-white text-brand-600 rounded-2xl font-bold hover:scale-105 transition-transform">
{t('cta_free_account')}
</Link>
<Link href="/signin" className="px-8 py-4 bg-brand-700 text-white rounded-2xl font-bold hover:bg-brand-800 transition-colors">
{t('cta_signin_portal')}
</Link>
</div>
</div>
{/* Abstract Design */}
<div className="absolute top-0 left-0 w-full h-full opacity-10 pointer-events-none">
<CommonGridShape />
</div>
</div>
</div>
</section>
{/* Back to Top Button */}
<ScrollToTop />
</div>
);
}