187 lines
8.1 KiB
TypeScript
187 lines
8.1 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import Link from "next/link";
|
||
|
|
import { useState } from "react";
|
||
|
|
import { ArrowRight } from "lucide-react";
|
||
|
|
import {
|
||
|
|
personalServices,
|
||
|
|
businessServices,
|
||
|
|
mobileQuickServices,
|
||
|
|
type ServiceCategory,
|
||
|
|
} from "@/features/landing-page/data";
|
||
|
|
import { useInView } from "@/features/landing-page/hooks";
|
||
|
|
|
||
|
|
interface HeroSectionProps {
|
||
|
|
heroCTARef: React.RefObject<HTMLDivElement | null>;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function HeroSection({ heroCTARef }: HeroSectionProps) {
|
||
|
|
const [heroRef, heroInView] = useInView();
|
||
|
|
const [activeCategory, setActiveCategory] = useState<ServiceCategory>("personal");
|
||
|
|
|
||
|
|
return (
|
||
|
|
<section
|
||
|
|
ref={heroRef as React.RefObject<HTMLElement>}
|
||
|
|
className={`relative left-1/2 right-1/2 w-screen -translate-x-1/2 py-12 sm:py-16 overflow-hidden transition-all duration-700 ${
|
||
|
|
heroInView ? "opacity-100 translate-y-0" : "opacity-0 translate-y-8"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
{/* Gradient Background */}
|
||
|
|
<div className="absolute inset-0 bg-gradient-to-br from-surface-sunken via-background to-info-bg/80" />
|
||
|
|
|
||
|
|
{/* Dot Grid Pattern Overlay */}
|
||
|
|
<div
|
||
|
|
className="absolute inset-0 pointer-events-none"
|
||
|
|
style={{
|
||
|
|
backgroundImage: `radial-gradient(circle at center, oklch(0.65 0.05 234.4 / 0.15) 1px, transparent 1px)`,
|
||
|
|
backgroundSize: "24px 24px",
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
|
||
|
|
{/* Subtle gradient accent in corner */}
|
||
|
|
<div
|
||
|
|
className="absolute -top-32 -right-32 w-96 h-96 rounded-full pointer-events-none"
|
||
|
|
style={{
|
||
|
|
background: "radial-gradient(circle, oklch(0.85 0.08 200 / 0.3) 0%, transparent 70%)",
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
|
||
|
|
<div className="relative mx-auto max-w-6xl grid grid-cols-1 lg:grid-cols-[1.05fr_minmax(0,0.95fr)] items-center gap-10 lg:gap-16 px-6 sm:px-10 lg:px-14">
|
||
|
|
<div className="space-y-6 text-left max-w-2xl">
|
||
|
|
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-extrabold leading-tight text-foreground">
|
||
|
|
<span className="block whitespace-nowrap">A One Stop Solution</span>
|
||
|
|
<span className="block text-primary mt-2 whitespace-nowrap">for Your IT Needs</span>
|
||
|
|
</h1>
|
||
|
|
<p className="text-base sm:text-lg text-muted-foreground leading-relaxed font-semibold">
|
||
|
|
No Japanese required. Get reliable internet, mobile, and VPN services with full English
|
||
|
|
support. Serving expats and international businesses for over 20 years.
|
||
|
|
</p>
|
||
|
|
<div
|
||
|
|
ref={heroCTARef}
|
||
|
|
className="flex flex-col sm:flex-row items-start sm:items-center gap-3 sm:gap-4 pt-2"
|
||
|
|
>
|
||
|
|
<Link
|
||
|
|
href="/services"
|
||
|
|
className="inline-flex items-center justify-center gap-2 rounded-full px-6 sm:px-8 py-3 text-base font-semibold bg-primary text-primary-foreground hover:bg-primary/90 shadow-md shadow-primary/20 transition-transform hover:-translate-y-0.5"
|
||
|
|
>
|
||
|
|
Browse Services
|
||
|
|
<ArrowRight className="h-5 w-5" />
|
||
|
|
</Link>
|
||
|
|
<Link
|
||
|
|
href="/contact"
|
||
|
|
className="inline-flex items-center justify-center gap-2 rounded-full px-6 sm:px-8 py-3 text-base font-semibold border border-border bg-card text-primary hover:bg-primary/5 transition-colors"
|
||
|
|
>
|
||
|
|
Need Assistance?
|
||
|
|
</Link>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Mobile Quick Services - visible on mobile only */}
|
||
|
|
<div className="lg:hidden w-full">
|
||
|
|
<div
|
||
|
|
className="flex gap-3 overflow-x-auto pb-4 snap-x snap-mandatory"
|
||
|
|
style={{ scrollbarWidth: "none" }}
|
||
|
|
>
|
||
|
|
{mobileQuickServices.map(service => (
|
||
|
|
<Link
|
||
|
|
key={service.title}
|
||
|
|
href={service.href}
|
||
|
|
className="flex-shrink-0 w-[140px] snap-start group"
|
||
|
|
>
|
||
|
|
<div className="flex flex-col items-center gap-2 p-4 rounded-xl border border-border/70 bg-card shadow-sm hover:shadow-md transition-shadow">
|
||
|
|
<div className="w-12 h-12 rounded-full border-2 border-primary/30 flex items-center justify-center group-hover:border-primary/60 transition-colors">
|
||
|
|
<div className="[&>svg]:h-6 [&>svg]:w-6">{service.icon}</div>
|
||
|
|
</div>
|
||
|
|
<span className="text-xs font-semibold text-foreground text-center">
|
||
|
|
{service.title}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</Link>
|
||
|
|
))}
|
||
|
|
<Link href="/services" className="flex-shrink-0 w-[140px] snap-start group">
|
||
|
|
<div className="flex flex-col items-center justify-center gap-2 p-4 rounded-xl border border-dashed border-primary/40 bg-primary/5 h-full min-h-[120px] hover:bg-primary/10 transition-colors">
|
||
|
|
<ArrowRight className="h-6 w-6 text-primary" />
|
||
|
|
<span className="text-xs font-semibold text-primary text-center">
|
||
|
|
See All Services
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</Link>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Desktop Services Panel - hidden on mobile */}
|
||
|
|
<div className="hidden lg:block relative w-full">
|
||
|
|
<div className="rounded-2xl border border-border/70 bg-card shadow-lg p-6">
|
||
|
|
{/* Tab Switcher */}
|
||
|
|
<div className="flex mb-6 bg-muted rounded-full p-1">
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={() => setActiveCategory("personal")}
|
||
|
|
className={`flex-1 py-2.5 px-4 text-sm font-semibold rounded-full transition-all ${
|
||
|
|
activeCategory === "personal"
|
||
|
|
? "bg-foreground text-background shadow-md"
|
||
|
|
: "text-muted-foreground hover:text-foreground"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
Personal Services
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={() => setActiveCategory("business")}
|
||
|
|
className={`flex-1 py-2.5 px-4 text-sm font-semibold rounded-full transition-all ${
|
||
|
|
activeCategory === "business"
|
||
|
|
? "bg-foreground text-background shadow-md"
|
||
|
|
: "text-muted-foreground hover:text-foreground"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
Business Services
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Services Grid */}
|
||
|
|
<div className="grid grid-cols-2 gap-3 h-[320px] content-start overflow-hidden">
|
||
|
|
{(activeCategory === "personal" ? personalServices : businessServices).map(
|
||
|
|
service => (
|
||
|
|
<Link
|
||
|
|
key={service.title}
|
||
|
|
href={service.href}
|
||
|
|
className={`group flex flex-col items-center justify-center gap-2 p-3 rounded-xl hover:bg-muted/50 transition-colors ${
|
||
|
|
activeCategory === "personal" ? "h-[152px]" : "h-[100px]"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
<div
|
||
|
|
className={`rounded-full border-2 border-primary/30 flex items-center justify-center group-hover:border-primary/60 transition-colors flex-shrink-0 ${
|
||
|
|
activeCategory === "personal" ? "w-20 h-20" : "w-14 h-14"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
<div
|
||
|
|
className={
|
||
|
|
activeCategory === "personal"
|
||
|
|
? "[&>svg]:h-10 [&>svg]:w-10"
|
||
|
|
: "[&>svg]:h-7 [&>svg]:w-7"
|
||
|
|
}
|
||
|
|
>
|
||
|
|
{service.icon}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<span
|
||
|
|
className={`font-semibold text-foreground text-center leading-tight ${
|
||
|
|
activeCategory === "personal" ? "text-sm" : "text-xs"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
{service.title}
|
||
|
|
</span>
|
||
|
|
</Link>
|
||
|
|
)
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Gradient fade to next section */}
|
||
|
|
<div className="absolute bottom-0 left-0 right-0 h-24 bg-gradient-to-b from-transparent to-background pointer-events-none" />
|
||
|
|
</section>
|
||
|
|
);
|
||
|
|
}
|