new creative section in services single
This commit is contained in:
26
package-lock.json
generated
26
package-lock.json
generated
@@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"framer-motion": "^12.38.0",
|
||||
"lucide-react": "^1.14.0",
|
||||
"motion": "^12.0.6",
|
||||
"next": "16.2.5",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "19.2.4",
|
||||
@@ -1358,6 +1359,31 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/motion": {
|
||||
"version": "12.38.0",
|
||||
"resolved": "https://registry.npmjs.org/motion/-/motion-12.38.0.tgz",
|
||||
"integrity": "sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w==",
|
||||
"dependencies": {
|
||||
"framer-motion": "^12.38.0",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"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
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/motion-dom": {
|
||||
"version": "12.38.0",
|
||||
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"framer-motion": "^12.38.0",
|
||||
"lucide-react": "^1.14.0",
|
||||
"motion": "^12.0.6",
|
||||
"next": "16.2.5",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "19.2.4",
|
||||
|
||||
@@ -10,6 +10,9 @@ import {
|
||||
Cloud,
|
||||
Database,
|
||||
Gauge,
|
||||
HandCoins,
|
||||
MousePointerClick,
|
||||
BarChart3,
|
||||
Headphones,
|
||||
Rocket,
|
||||
ShieldCheck,
|
||||
@@ -18,6 +21,7 @@ import {
|
||||
import { useI18n } from '../../../../i18n/provider';
|
||||
import { serviceContent, type ServiceSlug } from './services.data';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { NetworkNexus } from '../../../components/network-nexus';
|
||||
|
||||
function HeroIcon({ name }: { name: 'shield' | 'wp' | 'speed' | 'support' }) {
|
||||
const className =
|
||||
@@ -82,12 +86,12 @@ export default function ServiceDetailPage({ slug }: { slug: ServiceSlug }) {
|
||||
const { locale } = useI18n();
|
||||
const content = useMemo(() => serviceContent[slug][locale], [slug, locale]);
|
||||
const dir = locale === 'en' ? 'ltr' : 'rtl';
|
||||
const [openFaq, setOpenFaq] = useState<number>(0);
|
||||
const { resolvedTheme } = useTheme();
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => setMounted(true), []);
|
||||
|
||||
|
||||
const sectionMotion = {
|
||||
initial: { opacity: 0, y: 24 },
|
||||
whileInView: { opacity: 1, y: 0 },
|
||||
@@ -304,6 +308,9 @@ export default function ServiceDetailPage({ slug }: { slug: ServiceSlug }) {
|
||||
</div>
|
||||
</motion.section>
|
||||
|
||||
{/* Network architecture (Core hub) */}
|
||||
<NetworkNexus />
|
||||
|
||||
{/* Plans */}
|
||||
<motion.section {...sectionMotion} className="max-w-7xl mx-auto px-6 lg:px-10 pt-24">
|
||||
<div className="text-center mb-12">
|
||||
@@ -358,78 +365,74 @@ export default function ServiceDetailPage({ slug }: { slug: ServiceSlug }) {
|
||||
</div>
|
||||
</motion.section>
|
||||
|
||||
{/* FAQ + Why */}
|
||||
{/* FAQ (new layout) */}
|
||||
<motion.section {...sectionMotion} className="max-w-7xl mx-auto px-6 lg:px-10 pt-24">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6 items-stretch">
|
||||
<div className="lg:col-span-7 rounded-3xl border border-[color:var(--border-10)] bg-[color:var(--glass-04)] p-6 lg:p-8">
|
||||
<h2 className="text-xl lg:text-2xl font-bold mb-2">{content.faqTitle}</h2>
|
||||
<p className="text-sm text-[color:var(--text-muted)] mb-6">{content.faqSubtitle}</p>
|
||||
<div className="text-center mb-10">
|
||||
<h2 className="text-2xl sm:text-3xl font-bold text-[color:var(--text-primary)]">
|
||||
<span className="faq-title-bars">{content.faqTitle}</span>
|
||||
</h2>
|
||||
<p className="mt-3 text-sm sm:text-base text-[color:var(--text-muted)]">{content.faqSubtitle}</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
{content.faqs.map((f, idx) => {
|
||||
const isOpen = openFaq === idx;
|
||||
return (
|
||||
<div
|
||||
key={f.q}
|
||||
className="rounded-2xl border border-[color:var(--border-10)] bg-[color:var(--glass-02)] overflow-hidden"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOpenFaq(isOpen ? -1 : idx)}
|
||||
className="w-full flex items-center justify-between gap-4 px-4 py-4 text-right en-text-left"
|
||||
>
|
||||
<span className="text-sm font-semibold">{f.q}</span>
|
||||
<ChevronDown
|
||||
className={[
|
||||
'w-5 h-5 text-[color:var(--text-muted-2)] transition-transform',
|
||||
isOpen ? 'rotate-180' : 'rotate-0',
|
||||
].join(' ')}
|
||||
/>
|
||||
</button>
|
||||
{isOpen ? (
|
||||
<div className="px-4 pb-4 text-sm text-[color:var(--text-muted)] leading-relaxed">
|
||||
{f.a}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="relative max-w-5xl mx-auto">
|
||||
{/* Timeline spine (desktop) */}
|
||||
<div className="hidden md:block absolute right-[132px] top-0 bottom-0 w-px bg-gradient-to-b from-transparent via-[#80c8f5]/35 to-transparent" />
|
||||
|
||||
<div className="space-y-4">
|
||||
{content.faqs.map((f, idx) => {
|
||||
const Icon = [HandCoins, Gauge, ShieldCheck, MousePointerClick, BarChart3][idx % 5];
|
||||
const num = String(idx + 1).padStart(2, '0');
|
||||
const glow = ['#80c8f5', '#a78bfa', '#84e1bc', '#60a5fa', '#22d3ee'][idx % 5];
|
||||
|
||||
return (
|
||||
<div key={f.q} className="grid grid-cols-1 md:grid-cols-[1fr_220px] gap-5 items-stretch">
|
||||
<div className="relative rounded-2xl overflow-hidden border border-[color:var(--border-10)] bg-[color:var(--glass-04)] backdrop-blur-md">
|
||||
<div className="absolute inset-0 pointer-events-none opacity-70">
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-white/5 via-transparent to-transparent" />
|
||||
<div className="absolute inset-y-0 right-0 w-px bg-gradient-to-b from-transparent via-white/10 to-transparent" />
|
||||
</div>
|
||||
<div className="relative px-6 py-5">
|
||||
<div className="text-base sm:text-lg font-bold text-[color:var(--text-primary)] mb-2">{f.q}</div>
|
||||
<div className="text-sm text-[color:var(--text-muted)] leading-relaxed">{f.a}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="lg:col-span-5 rounded-3xl border border-[color:var(--border-10)] bg-[color:var(--glass-04)] p-6 lg:p-8 relative overflow-hidden">
|
||||
<div className="absolute inset-0 opacity-70 pointer-events-none">
|
||||
<div className="absolute -top-24 -right-24 w-72 h-72 bg-[#84e1bc]/10 blur-3xl rounded-full" />
|
||||
<div className="absolute -bottom-24 -left-24 w-72 h-72 bg-[#80c8f5]/10 blur-3xl rounded-full" />
|
||||
</div>
|
||||
<div className="hidden md:flex items-center justify-end relative">
|
||||
{/* Dot on spine */}
|
||||
<span
|
||||
className="absolute right-[132px] w-2 h-2 rounded-full"
|
||||
style={{ backgroundColor: glow, boxShadow: `0 0 16px ${glow}aa` }}
|
||||
/>
|
||||
{/* Connector from dot to badge */}
|
||||
<span
|
||||
className="absolute right-[132px] h-px w-[44px]"
|
||||
style={{
|
||||
background: `linear-gradient(to left, ${glow}99, transparent)`,
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="relative">
|
||||
<h3 className="text-xl lg:text-2xl font-bold mb-3">{content.whyTitle}</h3>
|
||||
<p className="text-sm text-[color:var(--text-muted)] leading-relaxed mb-5">{content.whyText}</p>
|
||||
<ul className="space-y-3 text-sm text-[color:var(--text-muted)]">
|
||||
{content.whyBullets.map((b) => (
|
||||
<li key={b} className="flex items-center gap-2">
|
||||
<span className="w-5 h-5 rounded-full bg-[#84e1bc]/15 border border-[#84e1bc]/25 flex items-center justify-center">
|
||||
<Check className="w-3.5 h-3.5 text-[#84e1bc]" />
|
||||
</span>
|
||||
<span className="en-text-left">{b}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="flex items-center gap-3 pr-2">
|
||||
<div className="relative w-[66px] h-[66px] hex-clip gradient-border-anim bg-[color:var(--glass-04)]">
|
||||
<div className="absolute inset-[1.5px] hex-clip bg-[color:var(--global-surface-bg-80)] border border-[color:var(--border-05)] flex items-center justify-center">
|
||||
<Icon className="w-6 h-6" style={{ color: glow }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 relative aspect-[16/10] rounded-2xl overflow-hidden border border-[color:var(--border-10)] bg-white dark:bg-[color:var(--glass-02)]">
|
||||
<Image
|
||||
src={mounted && resolvedTheme === 'light' ? '/images/services-hero-light.png' : '/images/services-hero-dark.png'}
|
||||
alt=""
|
||||
fill
|
||||
unoptimized
|
||||
quality={100}
|
||||
sizes="(min-width: 1024px) 35vw, 100vw"
|
||||
className="object-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/40 to-transparent dark:from-black/50" />
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
className="h-px w-[18px]"
|
||||
style={{
|
||||
background: `linear-gradient(to left, ${glow}66, rgba(255,255,255,0.06))`,
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="w-[62px] h-[62px] rounded-2xl border border-[color:var(--border-10)] bg-[color:var(--glass-04)] backdrop-blur-md flex items-center justify-center text-[color:var(--text-primary)] font-bold text-lg">
|
||||
{num}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</motion.section>
|
||||
|
||||
295
src/app/components/network-nexus.tsx
Normal file
295
src/app/components/network-nexus.tsx
Normal file
@@ -0,0 +1,295 @@
|
||||
import React, { useState } from 'react';
|
||||
import { motion, AnimatePresence } from 'motion/react';
|
||||
import {
|
||||
Server, Cloud, Shield, HardDrive, Globe, Cpu,
|
||||
Activity, Lock, Zap
|
||||
} from 'lucide-react';
|
||||
|
||||
const SERVICES = [
|
||||
{
|
||||
id: 'cloud',
|
||||
title: 'هاست ابری اختصاصی',
|
||||
desc: 'پایداری ۹۹.۹۹٪ با زیرساخت تمام ابری و هاردهای NVMe Enterprise',
|
||||
icon: Cloud,
|
||||
color: '#3b82f6',
|
||||
x: 0,
|
||||
y: -220,
|
||||
stats: [
|
||||
{ label: 'Uptime', value: '99.99%' },
|
||||
{ label: 'Storage', value: 'NVMe SSD' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'dedicated',
|
||||
title: 'سرور اختصاصی',
|
||||
desc: 'بالاترین قدرت پردازشی با <20><>رورهای فیزیکی اختصاصی در بهترین دیتاسنترها',
|
||||
icon: Server,
|
||||
color: '#ef4444',
|
||||
x: -300,
|
||||
y: -100,
|
||||
stats: [
|
||||
{ label: 'CPU', value: 'Intel/AMD Dual' },
|
||||
{ label: 'Network', value: '10 Gbps' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'vps',
|
||||
title: 'سرور مجازی (VPS)',
|
||||
desc: 'منابع کاملاً اختصاصی، کنترل کامل روت و تنوع سیستمعاملها',
|
||||
icon: HardDrive,
|
||||
color: '#10b981',
|
||||
x: 300,
|
||||
y: -100,
|
||||
stats: [
|
||||
{ label: 'RAM', value: 'Up to 128GB' },
|
||||
{ label: 'Root Access', value: 'Full' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'security',
|
||||
title: 'امنیت و آنتی دیداس',
|
||||
desc: 'محافظت هوشمند لایه ۷ در برابر بزرگترین حملات سایبری',
|
||||
icon: Shield,
|
||||
color: '#8b5cf6',
|
||||
x: -220,
|
||||
y: 160,
|
||||
stats: [
|
||||
{ label: 'DDoS Protection', value: 'Up to 2Tbps' },
|
||||
{ label: 'WAF', value: 'Enabled' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'cdn',
|
||||
title: 'شبکه توزیع محتوا (CDN)',
|
||||
desc: 'بارگذاری در کسری از ثانیه با توزیع جهانی اطلاعات در سرورهای لبه',
|
||||
icon: Globe,
|
||||
color: '#f59e0b',
|
||||
x: 220,
|
||||
y: 160,
|
||||
stats: [
|
||||
{ label: 'Global PoPs', value: '150+' },
|
||||
{ label: 'Latency', value: '< 20ms' }
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
export function NetworkNexus() {
|
||||
const [activeService, setActiveService] = useState<string | null>(null);
|
||||
|
||||
return (
|
||||
<section className="relative min-h-[120vh] flex flex-col items-center justify-center py-20 overflow-hidden bg-[#030014]" dir="rtl">
|
||||
|
||||
{/* Background Grid Pattern */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-10"
|
||||
style={{
|
||||
backgroundImage: 'radial-gradient(#4f46e5 1px, transparent 1px)',
|
||||
backgroundSize: '40px 40px',
|
||||
backgroundPosition: '-19px -19px'
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="text-center mb-16 z-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
whileInView={{ opacity: 1, scale: 1 }}
|
||||
className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-indigo-500/10 border border-indigo-500/30 text-indigo-400 text-sm mb-6"
|
||||
>
|
||||
<Activity className="w-4 h-4" />
|
||||
<span>زیرساخت ابری هوشمند و یکپارچه</span>
|
||||
</motion.div>
|
||||
<h2 className="text-4xl md:text-5xl font-bold mb-6 text-transparent bg-clip-text bg-gradient-to-r from-white via-indigo-200 to-gray-400">
|
||||
معماری شبکـه و سرورهـا
|
||||
</h2>
|
||||
<p className="text-gray-400 text-lg max-w-2xl mx-auto leading-relaxed">
|
||||
یک شبکه عظیم و به هم پیوسته از قدرتمندترین سرورهای جهان؛ پایداری بینظیر، امنیت لایهای و سرعت حداکثری برای کسبوکار شما.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="relative flex items-center justify-center w-full max-w-[1000px] h-[600px] mt-10 scale-[0.6] sm:scale-75 md:scale-100 transition-transform duration-500">
|
||||
|
||||
{/* SVG Connections */}
|
||||
<svg
|
||||
className="absolute inset-0 w-full h-full pointer-events-none"
|
||||
viewBox="-500 -300 1000 600"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
>
|
||||
<defs>
|
||||
<radialGradient id="coreGlow" cx="50%" cy="50%" r="50%">
|
||||
<stop offset="0%" stopColor="rgba(99, 102, 241, 0.4)" />
|
||||
<stop offset="100%" stopColor="rgba(99, 102, 241, 0)" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
|
||||
{/* Central Glow Effect */}
|
||||
<circle cx="0" cy="0" r="150" fill="url(#coreGlow)" className="animate-pulse" />
|
||||
|
||||
{/* Static paths and animated data streams */}
|
||||
{SERVICES.map((service) => {
|
||||
// Cubic bezier curve path for a "cable" look
|
||||
const pathD = `M 0 0 C ${service.x * 0.5} 0, ${service.x * 0.8} ${service.y * 0.8}, ${service.x} ${service.y}`;
|
||||
const isActive = activeService === service.id;
|
||||
const opacity = activeService ? (isActive ? 1 : 0.2) : 0.6;
|
||||
|
||||
return (
|
||||
<g key={`path-${service.id}`} className="transition-opacity duration-300" style={{ opacity }}>
|
||||
{/* Background cable */}
|
||||
<path
|
||||
d={pathD}
|
||||
fill="none"
|
||||
stroke="rgba(255,255,255,0.05)"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
|
||||
{/* Glowing packet stream */}
|
||||
<motion.path
|
||||
d={pathD}
|
||||
fill="none"
|
||||
stroke={service.color}
|
||||
strokeWidth="3"
|
||||
strokeDasharray="4 30"
|
||||
animate={{
|
||||
strokeDashoffset: isActive ? [-100, 0] : [100, 0]
|
||||
}}
|
||||
transition={{
|
||||
duration: isActive ? 1 : 3,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
style={{
|
||||
filter: `drop-shadow(0 0 8px ${service.color})`
|
||||
}}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
})}
|
||||
</svg>
|
||||
|
||||
{/* Central Hub (Core Data Center) */}
|
||||
<div
|
||||
className="absolute z-30 flex flex-col items-center justify-center w-40 h-40 rounded-3xl bg-[#0a0a1a] border border-indigo-500/50 shadow-[0_0_80px_rgba(99,102,241,0.4)]"
|
||||
style={{ transform: 'translate(-50%, -50%)', left: '50%', top: '50%' }}
|
||||
>
|
||||
<div className="absolute inset-0 rounded-3xl border-2 border-indigo-500/30 animate-ping opacity-20" />
|
||||
|
||||
<Cpu className="w-16 h-16 text-indigo-400 mb-2" />
|
||||
<div className="flex gap-1 mb-2">
|
||||
{[1,2,3].map(i => (
|
||||
<motion.div
|
||||
key={i}
|
||||
animate={{ opacity: [0.3, 1, 0.3] }}
|
||||
transition={{ duration: 1.5, repeat: Infinity, delay: i * 0.2 }}
|
||||
className="w-2 h-2 rounded-full bg-indigo-400 shadow-[0_0_5px_#818cf8]"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<span className="font-bold text-white text-sm tracking-widest">CORE HUB</span>
|
||||
</div>
|
||||
|
||||
{/* Service Nodes */}
|
||||
{SERVICES.map((service) => {
|
||||
const isActive = activeService === service.id;
|
||||
const isFaded = activeService && !isActive;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={`node-${service.id}`}
|
||||
className="absolute z-40 transition-all duration-500"
|
||||
style={{
|
||||
transform: `translate(-50%, -50%)`,
|
||||
left: `calc(50% + ${service.x}px)`,
|
||||
top: `calc(50% + ${service.y}px)`,
|
||||
opacity: isFaded ? 0.4 : 1,
|
||||
scale: isActive ? 1.1 : (isFaded ? 0.9 : 1),
|
||||
}}
|
||||
onMouseEnter={() => setActiveService(service.id)}
|
||||
onMouseLeave={() => setActiveService(null)}
|
||||
>
|
||||
<div
|
||||
className="relative group cursor-pointer"
|
||||
>
|
||||
{/* Icon Container */}
|
||||
<div
|
||||
className="relative flex items-center justify-center w-20 h-20 rounded-2xl bg-[#0f0f29] border-2 transition-all duration-300 overflow-hidden"
|
||||
style={{
|
||||
borderColor: isActive ? service.color : 'rgba(255,255,255,0.1)',
|
||||
boxShadow: isActive ? `0 0 30px ${service.color}60` : `0 0 15px rgba(0,0,0,0.5)`,
|
||||
}}
|
||||
>
|
||||
{/* Hover gradient background inside the node */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-0 group-hover:opacity-20 transition-opacity duration-300"
|
||||
style={{ background: `radial-gradient(circle at center, ${service.color}, transparent)` }}
|
||||
/>
|
||||
<service.icon
|
||||
size={32}
|
||||
className="transition-colors duration-300"
|
||||
style={{ color: isActive ? '#fff' : service.color }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Floating Info Card (Shows on Hover/Active) */}
|
||||
<AnimatePresence>
|
||||
{isActive && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10, scale: 0.95 }}
|
||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||
exit={{ opacity: 0, y: 5, scale: 0.95 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
className="absolute top-24 left-1/2 -translate-x-1/2 w-[300px] p-5 rounded-2xl bg-[#13132f]/95 backdrop-blur-xl border border-white/10 shadow-2xl z-50 pointer-events-none"
|
||||
>
|
||||
<h4 className="text-xl font-bold mb-2 text-white flex items-center gap-2">
|
||||
<span className="w-2 h-2 rounded-full" style={{ backgroundColor: service.color, boxShadow: `0 0 10px ${service.color}` }} />
|
||||
{service.title}
|
||||
</h4>
|
||||
<p className="text-sm text-gray-400 mb-4 leading-relaxed">
|
||||
{service.desc}
|
||||
</p>
|
||||
|
||||
<div className="space-y-2 pt-3 border-t border-white/5">
|
||||
{service.stats.map((stat, idx) => (
|
||||
<div key={idx} className="flex justify-between items-center text-xs">
|
||||
<span className="text-gray-500 font-mono">{stat.label}</span>
|
||||
<span className="text-indigo-300 font-bold bg-indigo-500/10 px-2 py-1 rounded">
|
||||
{stat.value}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* Label (when not hovered) */}
|
||||
<div
|
||||
className={`absolute -bottom-8 left-1/2 -translate-x-1/2 whitespace-nowrap text-sm font-medium transition-opacity duration-300 ${isActive ? 'opacity-0' : 'opacity-100 text-gray-300'}`}
|
||||
>
|
||||
{service.title}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Decorative Server Rack Elements on the sides */}
|
||||
<div className="hidden lg:flex absolute right-4 top-1/2 -translate-y-1/2 flex-col gap-2 opacity-20 pointer-events-none">
|
||||
{[1,2,3,4,5].map(i => (
|
||||
<div key={i} className="w-16 h-8 border border-white/20 rounded bg-white/5 flex items-center px-2 gap-1">
|
||||
<div className="w-1 h-1 rounded-full bg-green-500 animate-pulse" style={{ animationDelay: `${i*0.3}s` }}/>
|
||||
<div className="w-1 h-1 rounded-full bg-blue-500" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="hidden lg:flex absolute left-4 top-1/2 -translate-y-1/2 flex-col gap-2 opacity-20 pointer-events-none">
|
||||
{[1,2,3,4,5].map(i => (
|
||||
<div key={i} className="w-16 h-8 border border-white/20 rounded bg-white/5 flex items-center justify-end px-2 gap-1">
|
||||
<div className="w-1 h-1 rounded-full bg-green-500 animate-pulse" style={{ animationDelay: `${i*0.5}s` }}/>
|
||||
<div className="w-1 h-1 rounded-full bg-blue-500" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -28,7 +28,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rb-fade-in {
|
||||
@keyframes rb-fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
@@ -93,6 +93,110 @@ html.light .glass-rotating-border::after {
|
||||
filter: blur(16px);
|
||||
}
|
||||
|
||||
/* Animated gradient border (FAQ cards / hex badges) */
|
||||
@property --gb-angle {
|
||||
syntax: '<angle>';
|
||||
inherits: false;
|
||||
initial-value: 0deg;
|
||||
}
|
||||
|
||||
@keyframes gb-spin {
|
||||
to {
|
||||
--gb-angle: 360deg;
|
||||
}
|
||||
}
|
||||
|
||||
.gradient-border-anim {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.gradient-border-anim::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
padding: 1.5px;
|
||||
pointer-events: none;
|
||||
background: conic-gradient(
|
||||
from var(--gb-angle),
|
||||
rgba(255, 255, 255, 0) 0deg,
|
||||
rgba(128, 200, 245, 0.55) 70deg,
|
||||
rgba(167, 139, 250, 0.50) 145deg,
|
||||
rgba(132, 225, 188, 0.50) 225deg,
|
||||
rgba(34, 211, 238, 0.45) 305deg,
|
||||
rgba(255, 255, 255, 0) 360deg
|
||||
);
|
||||
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
filter: drop-shadow(0 0 18px rgba(128, 200, 245, 0.10));
|
||||
animation: gb-spin 6.5s linear infinite;
|
||||
}
|
||||
|
||||
.gradient-border-anim::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: -10px;
|
||||
border-radius: inherit;
|
||||
pointer-events: none;
|
||||
background: conic-gradient(
|
||||
from var(--gb-angle),
|
||||
rgba(255, 255, 255, 0) 0deg,
|
||||
rgba(128, 200, 245, 0.18) 90deg,
|
||||
rgba(167, 139, 250, 0.14) 170deg,
|
||||
rgba(132, 225, 188, 0.14) 250deg,
|
||||
rgba(34, 211, 238, 0.12) 330deg,
|
||||
rgba(255, 255, 255, 0) 360deg
|
||||
);
|
||||
filter: blur(18px);
|
||||
opacity: 0.65;
|
||||
animation: gb-spin 6.5s linear infinite;
|
||||
}
|
||||
|
||||
html.light .gradient-border-anim::before {
|
||||
filter: drop-shadow(0 0 14px rgba(2, 6, 23, 0.06));
|
||||
}
|
||||
|
||||
.hex-clip {
|
||||
clip-path: polygon(25% 6%, 75% 6%, 100% 50%, 75% 94%, 25% 94%, 0% 50%);
|
||||
}
|
||||
|
||||
.faq-title-bars {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.faq-title-bars::before,
|
||||
.faq-title-bars::after {
|
||||
content: '';
|
||||
width: 44px;
|
||||
height: 10px;
|
||||
background:
|
||||
linear-gradient(90deg, rgba(128,200,245,0) 0%,
|
||||
rgba(128,200,245,0) 22%,
|
||||
rgba(167,139,250,0.85) 22%,
|
||||
rgba(167,139,250,0.85) 34%,
|
||||
rgba(128,200,245,0) 34%,
|
||||
rgba(128,200,245,0) 44%,
|
||||
rgba(128,200,245,0.85) 44%,
|
||||
rgba(128,200,245,0.85) 56%,
|
||||
rgba(128,200,245,0) 56%,
|
||||
rgba(128,200,245,0) 66%,
|
||||
rgba(96,165,250,0.85) 66%,
|
||||
rgba(96,165,250,0.85) 78%,
|
||||
rgba(128,200,245,0) 78%,
|
||||
rgba(128,200,245,0) 100%);
|
||||
-webkit-mask: linear-gradient(135deg, #000 0 0);
|
||||
mask: linear-gradient(135deg, #000 0 0);
|
||||
transform: skewX(-18deg);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.faq-title-bars::after {
|
||||
transform: scaleX(-1) skewX(-18deg);
|
||||
}
|
||||
|
||||
html.light .glass-rotating-border::before {
|
||||
background: conic-gradient(
|
||||
rgba(255, 255, 255, 0) 0deg 28deg,
|
||||
|
||||
Reference in New Issue
Block a user